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