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
15static void skipped()
16{
17 std::cout << "skipped\n";
18}
19
20int
21main()
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
42static boost::mutex simple_mutex;
43static int simple_definition_count = 0;
44
45struct simple : public BOOST_SPIRIT_CLASSIC_NS::grammar<simple>
46{
47 template <typename ScannerT>
48 struct definition
49 {
50 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;
58 BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> const &start() const { return top; }
59 };
60};
61
62struct count_guard
63{
64 count_guard(int &c) : counter(c) {}
65 ~count_guard() { counter = 0; }
66private:
67 int &counter;
68};
69
70static void
71milli_sleep(unsigned long milliseconds)
72{
73 static long const nanoseconds_per_second = 1000L*1000L*1000L;
74 boost::xtime xt;
75 boost::xtime_get(xtp: &xt, clock_type: 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
86static void
87nap()
88{
89 // this function is called by various threads to ensure
90 // that thread lifetime actually overlap
91 milli_sleep(milliseconds: 300);
92}
93
94template <typename GrammarT>
95static void
96make_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
104template <typename GrammarT>
105static void
106make_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////////////////////////////////////////////////////////////////////////////////
123static void
124multiple_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(g&: simple1_p);
135 make_definition(g&: simple1_p);
136 make_definition(g&: simple1_p);
137
138 BOOST_TEST(exactly_one_instance_created);
139
140 make_definition(g&: simple2_p);
141 make_definition(g&: simple2_p);
142 make_definition(g&: simple2_p);
143
144 BOOST_TEST(exactly_two_instances_created);
145}
146
147////////////////////////////////////////////////////////////////////////////////
148struct single_grammar_object_task
149{
150 void operator()() const
151 {
152 make_definition3(g: simple1_p);
153 };
154
155 simple simple1_p;
156};
157////////////////////////////////////////////////////////////////////////////////
158template <typename T>
159class callable_reference_wrapper
160 : public boost::reference_wrapper<T>
161{
162public:
163 explicit callable_reference_wrapper(T& t)
164 : boost::reference_wrapper<T>(t)
165 {}
166 inline void operator()() { this->get().operator()(); }
167};
168
169template <typename T>
170callable_reference_wrapper<T>
171callable_ref(T &t)
172{
173 return callable_reference_wrapper<T>(t);
174}
175////////////////////////////////////////////////////////////////////////////////
176static void
177single_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(t&: task1));
185 boost::thread t2(callable_ref(t&: task2));
186 boost::thread t3(callable_ref(t&: task3));
187 boost::thread t4(callable_ref(t&: 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////////////////////////////////////////////////////////////////////////////////
198struct two_grammar_objects_task
199{
200 void operator()() const
201 {
202 make_definition3(g: simple1_p);
203 make_definition3(g: simple2_p);
204 };
205
206 simple simple1_p;
207 simple simple2_p;
208};
209
210static void
211multiple_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(t&: task1));
219 boost::thread t2(callable_ref(t&: task2));
220 boost::thread t3(callable_ref(t&: task3));
221 boost::thread t4(callable_ref(t&: 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////////////////////////////////////////////////////////////////////////////////
232static simple global_simple1_p;
233
234struct single_global_grammar_object_task
235{
236 void operator()() const
237 {
238 make_definition3(g&: global_simple1_p);
239 };
240};
241
242static void
243single_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(t&: task1));
251 boost::thread t2(callable_ref(t&: task2));
252 boost::thread t3(callable_ref(t&: task3));
253 boost::thread t4(callable_ref(t&: 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////////////////////////////////////////////////////////////////////////////////
264static simple global_simple2_p;
265static simple global_simple3_p;
266
267struct multiple_global_grammar_objects_task
268{
269 void operator()() const
270 {
271 make_definition3(g&: global_simple2_p);
272 make_definition3(g&: global_simple3_p);
273 };
274};
275
276static void
277multiple_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(t&: task1));
285 boost::thread t2(callable_ref(t&: task2));
286 boost::thread t3(callable_ref(t&: task3));
287 boost::thread t4(callable_ref(t&: task4));
288
289 t1.join();
290 t2.join();
291 t3.join();
292 t4.join();
293
294 BOOST_TEST(exactly_eight_instances_created);
295}
296////////////////////////////////////////////////////////////////////////////////
297int
298main()
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
311static 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

source code of boost/libs/spirit/classic/test/grammar_mt_tests.cpp