1 /*=============================================================================
2     Copyright (c) 2003 Martin Wille
3     http://spirit.sourceforge.net/
4 
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #include <iostream>
10 #include <boost/config.hpp>
11 #include <boost/detail/lightweight_test.hpp>
12 
13 #if defined(DONT_HAVE_BOOST) || !defined(BOOST_HAS_THREADS) || defined(BOOST_DISABLE_THREADS)
14 // we end here if we can't do multithreading
skipped()15 static void skipped()
16 {
17     std::cout << "skipped\n";
18 }
19 
20 int
main()21 main()
22 {
23     skipped();
24     return 0;
25 }
26 
27 #else
28 // the real MT stuff
29 
30 #undef BOOST_SPIRIT_THREADSAFE
31 #define BOOST_SPIRIT_THREADSAFE
32 
33 #include <boost/thread/thread.hpp>
34 #include <boost/spirit/include/classic_grammar.hpp>
35 #include <boost/spirit/include/classic_rule.hpp>
36 #include <boost/spirit/include/classic_epsilon.hpp>
37 #include <boost/thread/xtime.hpp>
38 #include <boost/thread/mutex.hpp>
39 #include <boost/thread/lock_types.hpp>
40 #include <boost/ref.hpp>
41 
42 static boost::mutex simple_mutex;
43 static int simple_definition_count = 0;
44 
45 struct simple : public BOOST_SPIRIT_CLASSIC_NS::grammar<simple>
46 {
47     template <typename ScannerT>
48     struct definition
49     {
definitionsimple::definition50         definition(simple const& /*self*/)
51         {
52             top = BOOST_SPIRIT_CLASSIC_NS::epsilon_p;
53             boost::unique_lock<boost::mutex> lock(simple_mutex);
54             simple_definition_count++;
55         }
56 
57         BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> top;
startsimple::definition58         BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> const &start() const { return top; }
59     };
60 };
61 
62 struct count_guard
63 {
count_guardcount_guard64     count_guard(int &c) : counter(c) {}
~count_guardcount_guard65     ~count_guard() { counter = 0; }
66 private:
67     int &counter;
68 };
69 
70 static void
milli_sleep(unsigned long milliseconds)71 milli_sleep(unsigned long milliseconds)
72 {
73     static long const nanoseconds_per_second = 1000L*1000L*1000L;
74     boost::xtime xt;
75     boost::xtime_get(&xt, boost::TIME_UTC_);
76     xt.nsec+=1000*1000*milliseconds;
77     while (xt.nsec > nanoseconds_per_second)
78     {
79         xt.nsec -= nanoseconds_per_second;
80         xt.sec++;
81     }
82 
83     boost::thread::sleep(xt);
84 }
85 
86 static void
nap()87 nap()
88 {
89     // this function is called by various threads to ensure
90     // that thread lifetime actually overlap
91     milli_sleep(300);
92 }
93 
94 template <typename GrammarT>
95 static void
make_definition(GrammarT & g)96 make_definition(GrammarT &g)
97 {
98     char const *text="blah";
99     BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
100 
101     g.parse(s);
102 }
103 
104 template <typename GrammarT>
105 static void
make_definition3(GrammarT & g)106 make_definition3(GrammarT &g)
107 {
108     char const *text="blah";
109     BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
110 
111     g.parse(s);
112     nap();
113     g.parse(s);
114     g.parse(s);
115 }
116 ////////////////////////////////////////////////////////////////////////////////
117 #define exactly_one_instance_created simple_definition_count == 1
118 #define exactly_two_instances_created simple_definition_count == 2
119 #define exactly_four_instances_created simple_definition_count == 4
120 #define exactly_eight_instances_created simple_definition_count == 8
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 static void
multiple_attempts_to_instantiate_a_definition_from_a_single_thread()124 multiple_attempts_to_instantiate_a_definition_from_a_single_thread()
125 {
126     // checks wether exactly one definition per grammar
127     // object is created
128 
129     count_guard guard(simple_definition_count);
130 
131     simple simple1_p;
132     simple simple2_p;
133 
134     make_definition(simple1_p);
135     make_definition(simple1_p);
136     make_definition(simple1_p);
137 
138     BOOST_TEST(exactly_one_instance_created);
139 
140     make_definition(simple2_p);
141     make_definition(simple2_p);
142     make_definition(simple2_p);
143 
144     BOOST_TEST(exactly_two_instances_created);
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 struct single_grammar_object_task
149 {
operator ()single_grammar_object_task150     void operator()() const
151     {
152         make_definition3(simple1_p);
153     };
154 
155     simple simple1_p;
156 };
157 ////////////////////////////////////////////////////////////////////////////////
158 template <typename T>
159 class callable_reference_wrapper
160     : public boost::reference_wrapper<T>
161 {
162 public:
callable_reference_wrapper(T & t)163     explicit callable_reference_wrapper(T& t)
164         : boost::reference_wrapper<T>(t)
165     {}
operator ()()166     inline void operator()() { this->get().operator()(); }
167 };
168 
169 template <typename T>
170 callable_reference_wrapper<T>
callable_ref(T & t)171 callable_ref(T &t)
172 {
173     return callable_reference_wrapper<T>(t);
174 }
175 ////////////////////////////////////////////////////////////////////////////////
176 static void
single_local_grammar_object_multiple_threads()177 single_local_grammar_object_multiple_threads()
178 {
179     // check wether independent definition objects are
180     // created
181     count_guard guard(simple_definition_count);
182     single_grammar_object_task task1, task2, task3, task4;
183 
184     boost::thread t1(callable_ref(task1));
185     boost::thread t2(callable_ref(task2));
186     boost::thread t3(callable_ref(task3));
187     boost::thread t4(callable_ref(task4));
188 
189     t1.join();
190     t2.join();
191     t3.join();
192     t4.join();
193 
194     BOOST_TEST(exactly_four_instances_created);
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 struct two_grammar_objects_task
199 {
operator ()two_grammar_objects_task200     void operator()() const
201     {
202         make_definition3(simple1_p);
203         make_definition3(simple2_p);
204     };
205 
206     simple simple1_p;
207     simple simple2_p;
208 };
209 
210 static void
multiple_local_grammar_objects_multiple_threads()211 multiple_local_grammar_objects_multiple_threads()
212 {
213     // check wether exactly one definition per thread
214     // and per grammar object is created
215     count_guard guard(simple_definition_count);
216     two_grammar_objects_task task1, task2, task3, task4;
217 
218     boost::thread t1(callable_ref(task1));
219     boost::thread t2(callable_ref(task2));
220     boost::thread t3(callable_ref(task3));
221     boost::thread t4(callable_ref(task4));
222 
223     t1.join();
224     t2.join();
225     t3.join();
226     t4.join();
227 
228     BOOST_TEST(exactly_eight_instances_created);
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 static simple global_simple1_p;
233 
234 struct single_global_grammar_object_task
235 {
operator ()single_global_grammar_object_task236     void operator()() const
237     {
238         make_definition3(global_simple1_p);
239     };
240 };
241 
242 static void
single_global_grammar_object_multiple_threads()243 single_global_grammar_object_multiple_threads()
244 {
245     // check wether exactly one definition per thread is
246     // created
247     count_guard guard(simple_definition_count);
248     single_global_grammar_object_task task1, task2, task3, task4;
249 
250     boost::thread t1(callable_ref(task1));
251     boost::thread t2(callable_ref(task2));
252     boost::thread t3(callable_ref(task3));
253     boost::thread t4(callable_ref(task4));
254 
255     t1.join();
256     t2.join();
257     t3.join();
258     t4.join();
259 
260     BOOST_TEST(exactly_four_instances_created);
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 static simple global_simple2_p;
265 static simple global_simple3_p;
266 
267 struct multiple_global_grammar_objects_task
268 {
operator ()multiple_global_grammar_objects_task269     void operator()() const
270     {
271         make_definition3(global_simple2_p);
272         make_definition3(global_simple3_p);
273     };
274 };
275 
276 static void
multiple_global_grammar_objects_multiple_threads()277 multiple_global_grammar_objects_multiple_threads()
278 {
279     // check wether exactly one definition per thread
280     // and per grammar object is created
281     count_guard guard(simple_definition_count);
282     multiple_global_grammar_objects_task task1, task2, task3, task4;
283 
284     boost::thread t1(callable_ref(task1));
285     boost::thread t2(callable_ref(task2));
286     boost::thread t3(callable_ref(task3));
287     boost::thread t4(callable_ref(task4));
288 
289     t1.join();
290     t2.join();
291     t3.join();
292     t4.join();
293 
294     BOOST_TEST(exactly_eight_instances_created);
295 }
296 ////////////////////////////////////////////////////////////////////////////////
297 int
main()298 main()
299 {
300     multiple_attempts_to_instantiate_a_definition_from_a_single_thread();
301     single_local_grammar_object_multiple_threads();
302     multiple_local_grammar_objects_multiple_threads();
303     single_global_grammar_object_multiple_threads();
304     multiple_global_grammar_objects_multiple_threads();
305 
306     return boost::report_errors();
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 
311 static BOOST_SPIRIT_CLASSIC_NS::parse_info<char const *> pi;
312 
313 ////////////////////////////////////////////////
314 // These macros are used with BOOST_TEST
315 
316 
317 
318 #endif // MT mode
319