• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 //          Copyright Oliver Kowalke 2013.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // This test is based on the tests of Boost.Thread
8 
9 #include <chrono>
10 #include <cstdlib>
11 #include <cstdio>
12 #include <iostream>
13 #include <map>
14 #include <stdexcept>
15 #include <vector>
16 
17 #include <boost/test/unit_test.hpp>
18 
19 #include <boost/fiber/all.hpp>
20 
21 typedef std::chrono::nanoseconds  ns;
22 typedef std::chrono::milliseconds ms;
23 
24 int value1 = 0;
25 
26 inline
delay(int secs,int msecs=0,int=0)27 std::chrono::system_clock::time_point delay(int secs, int msecs=0, int /*nsecs*/=0) {
28     std::chrono::system_clock::time_point t = std::chrono::system_clock::now();
29     t += std::chrono::seconds( secs);
30     t += std::chrono::milliseconds( msecs);
31     //t += std::chrono::nanoseconds( nsecs);
32 
33     return t;
34 }
35 
36 struct condition_test_data {
condition_test_datacondition_test_data37     condition_test_data() : notified(0), awoken(0) { }
38 
39     boost::fibers::mutex mutex;
40     boost::fibers::condition_variable_any cond;
41     int notified;
42     int awoken;
43 };
44 
condition_test_fiber(condition_test_data * data)45 void condition_test_fiber(condition_test_data* data) {
46     try {
47     data->mutex.lock();
48     while (!(data->notified > 0))
49         data->cond.wait(data->mutex);
50     data->awoken++;
51     } catch ( ... ) {
52     }
53     data->mutex.unlock();
54 }
55 
56 struct cond_predicate {
cond_predicatecond_predicate57     cond_predicate(int& var, int val) : _var(var), _val(val) { }
58 
operator ()cond_predicate59     bool operator()() { return _var == _val; }
60 
61     int& _var;
62     int _val;
63 private:
64     void operator=(cond_predicate&);
65 
66 };
67 
notify_one_fn(boost::fibers::condition_variable_any & cond)68 void notify_one_fn( boost::fibers::condition_variable_any & cond) {
69 	cond.notify_one();
70 }
71 
notify_all_fn(boost::fibers::condition_variable_any & cond)72 void notify_all_fn( boost::fibers::condition_variable_any & cond) {
73 	cond.notify_all();
74 }
75 
wait_fn(boost::fibers::mutex & mtx,boost::fibers::condition_variable_any & cond)76 void wait_fn(
77 	boost::fibers::mutex & mtx,
78 	boost::fibers::condition_variable_any & cond) {
79 	mtx.lock();
80 	cond.wait( mtx);
81 	++value1;
82     mtx.unlock();
83 }
84 
test_one_waiter_notify_one()85 void test_one_waiter_notify_one() {
86 	value1 = 0;
87 	boost::fibers::mutex mtx;
88 	boost::fibers::condition_variable_any cond;
89 
90     boost::fibers::fiber f1(
91                 boost::fibers::launch::post,
92                 wait_fn,
93                 std::ref( mtx),
94                 std::ref( cond) );
95 	BOOST_CHECK_EQUAL( 0, value1);
96 
97 	boost::fibers::fiber f2(
98                 boost::fibers::launch::post,
99                 notify_one_fn,
100                 std::ref( cond) );
101 
102 	BOOST_CHECK_EQUAL( 0, value1);
103 
104     f1.join();
105     f2.join();
106 
107 	BOOST_CHECK_EQUAL( 1, value1);
108 }
109 
test_two_waiter_notify_one()110 void test_two_waiter_notify_one() {
111 	value1 = 0;
112 	boost::fibers::mutex mtx;
113 	boost::fibers::condition_variable_any cond;
114 
115     boost::fibers::fiber f1(
116                 boost::fibers::launch::post,
117                 wait_fn,
118                 std::ref( mtx),
119                 std::ref( cond) );
120 	BOOST_CHECK_EQUAL( 0, value1);
121 
122     boost::fibers::fiber f2(
123                 boost::fibers::launch::post,
124                 wait_fn,
125                 std::ref( mtx),
126                 std::ref( cond) );
127 	BOOST_CHECK_EQUAL( 0, value1);
128 
129     boost::fibers::fiber f3(
130                 boost::fibers::launch::post,
131                 notify_one_fn,
132                 std::ref( cond) );
133 	BOOST_CHECK_EQUAL( 0, value1);
134 
135     boost::fibers::fiber f4(
136                 boost::fibers::launch::post,
137                 notify_one_fn,
138                 std::ref( cond) );
139 	BOOST_CHECK_EQUAL( 0, value1);
140 
141     f1.join();
142     f2.join();
143     f3.join();
144     f4.join();
145 
146 	BOOST_CHECK_EQUAL( 2, value1);
147 }
148 
test_two_waiter_notify_all()149 void test_two_waiter_notify_all() {
150 	value1 = 0;
151 	boost::fibers::mutex mtx;
152 	boost::fibers::condition_variable_any cond;
153 
154     boost::fibers::fiber f1(
155                 boost::fibers::launch::post,
156                 wait_fn,
157                 std::ref( mtx),
158                 std::ref( cond) );
159 	BOOST_CHECK_EQUAL( 0, value1);
160 
161     boost::fibers::fiber f2(
162                 boost::fibers::launch::post,
163                 wait_fn,
164                 std::ref( mtx),
165                 std::ref( cond) );
166 	BOOST_CHECK_EQUAL( 0, value1);
167 
168     boost::fibers::fiber f3(
169                 boost::fibers::launch::post,
170                 notify_all_fn,
171                 std::ref( cond) );
172 	BOOST_CHECK_EQUAL( 0, value1);
173 
174     boost::fibers::fiber f4(
175                 boost::fibers::launch::post,
176                 wait_fn,
177                 std::ref( mtx),
178                 std::ref( cond) );
179 	BOOST_CHECK_EQUAL( 0, value1);
180 
181     boost::fibers::fiber f5(
182                 boost::fibers::launch::post,
183                 notify_all_fn,
184                 std::ref( cond) );
185 	BOOST_CHECK_EQUAL( 0, value1);
186 
187     f1.join();
188     f2.join();
189     f3.join();
190     f4.join();
191     f5.join();
192 
193 	BOOST_CHECK_EQUAL( 3, value1);
194 }
195 
196 int test1 = 0;
197 int test2 = 0;
198 
199 int runs = 0;
200 
fn1(boost::fibers::mutex & m,boost::fibers::condition_variable_any & cv)201 void fn1( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) {
202     m.lock();
203     BOOST_CHECK(test2 == 0);
204     test1 = 1;
205     cv.notify_one();
206     while (test2 == 0) {
207         cv.wait(m);
208     }
209     BOOST_CHECK(test2 != 0);
210     m.unlock();
211 }
212 
fn2(boost::fibers::mutex & m,boost::fibers::condition_variable_any & cv)213 void fn2( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) {
214     m.lock();
215     BOOST_CHECK(test2 == 0);
216     test1 = 1;
217     cv.notify_one();
218     std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now();
219     std::chrono::system_clock::time_point t = t0 + ms(250);
220     int count=0;
221     while (test2 == 0 && cv.wait_until(m, t) == boost::fibers::cv_status::no_timeout)
222         count++;
223     std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();
224     if (runs == 0) {
225         BOOST_CHECK(t1 - t0 < ms(250));
226         BOOST_CHECK(test2 != 0);
227     } else {
228         BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000));
229         BOOST_CHECK(test2 == 0);
230     }
231     ++runs;
232     m.unlock();
233 }
234 
235 class Pred {
236      int    &   i_;
237 
238 public:
Pred(int & i)239     explicit Pred(int& i) :
240         i_(i)
241     {}
242 
operator ()()243     bool operator()()
244     { return i_ != 0; }
245 };
246 
fn3(boost::fibers::mutex & m,boost::fibers::condition_variable_any & cv)247 void fn3( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) {
248     m.lock();
249     BOOST_CHECK(test2 == 0);
250     test1 = 1;
251     cv.notify_one();
252     std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
253     std::chrono::steady_clock::time_point t = t0 + ms(250);
254     bool r = cv.wait_until(m, t, Pred(test2));
255     std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
256     if (runs == 0) {
257         BOOST_CHECK(t1 - t0 < ms(250));
258         BOOST_CHECK(test2 != 0);
259         BOOST_CHECK(r);
260     } else {
261         BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100));
262         BOOST_CHECK(test2 == 0);
263         BOOST_CHECK(!r);
264     }
265     ++runs;
266     m.unlock();
267 }
268 
fn4(boost::fibers::mutex & m,boost::fibers::condition_variable_any & cv)269 void fn4( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) {
270     m.lock();
271     BOOST_CHECK(test2 == 0);
272     test1 = 1;
273     cv.notify_one();
274     std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
275     int count=0;
276     while (test2 == 0 && cv.wait_for(m, ms(250)) == boost::fibers::cv_status::no_timeout)
277         count++;
278     std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
279     if (runs == 0) {
280         BOOST_CHECK(t1 - t0 < ms(250));
281         BOOST_CHECK(test2 != 0);
282     } else {
283         BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000));
284         BOOST_CHECK(test2 == 0);
285     }
286     ++runs;
287     m.unlock();
288 }
289 
fn5(boost::fibers::mutex & m,boost::fibers::condition_variable_any & cv)290 void fn5( boost::fibers::mutex & m, boost::fibers::condition_variable_any & cv) {
291     m.lock();
292     BOOST_CHECK(test2 == 0);
293     test1 = 1;
294     cv.notify_one();
295     std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
296     int count=0;
297     cv.wait_for(m, ms(250), Pred(test2));
298     count++;
299     std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
300     if (runs == 0) {
301         BOOST_CHECK(t1 - t0 < ms(250+1000));
302         BOOST_CHECK(test2 != 0);
303     } else {
304         BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100));
305         BOOST_CHECK(test2 == 0);
306     }
307     ++runs;
308     m.unlock();
309 }
310 
do_test_condition_wait()311 void do_test_condition_wait() {
312     test1 = 0;
313     test2 = 0;
314     runs = 0;
315 
316     boost::fibers::mutex m;
317     boost::fibers::condition_variable_any cv;
318     m.lock();
319     boost::fibers::fiber f( boost::fibers::launch::post, & fn1, std::ref( m), std::ref( cv) );
320     BOOST_CHECK(test1 == 0);
321     while (test1 == 0)
322         cv.wait(m);
323     BOOST_CHECK(test1 != 0);
324     test2 = 1;
325     m.unlock();
326     cv.notify_one();
327     f.join();
328 }
329 
test_condition_wait()330 void test_condition_wait() {
331     boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait).join();
332     do_test_condition_wait();
333 }
334 
do_test_condition_wait_until()335 void do_test_condition_wait_until() {
336     test1 = 0;
337     test2 = 0;
338     runs = 0;
339 
340     boost::fibers::mutex m;
341     boost::fibers::condition_variable_any cv;
342     {
343         m.lock();
344         boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) );
345         BOOST_CHECK(test1 == 0);
346         while (test1 == 0)
347             cv.wait(m);
348         BOOST_CHECK(test1 != 0);
349         test2 = 1;
350         m.unlock();
351         cv.notify_one();
352         f.join();
353     }
354     test1 = 0;
355     test2 = 0;
356     {
357         m.lock();
358         boost::fibers::fiber f( boost::fibers::launch::post, & fn2, std::ref( m), std::ref( cv) );
359         BOOST_CHECK(test1 == 0);
360         while (test1 == 0)
361             cv.wait(m);
362         BOOST_CHECK(test1 != 0);
363         m.unlock();
364         f.join();
365     }
366 }
367 
test_condition_wait_until()368 void test_condition_wait_until() {
369     boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until).join();
370     do_test_condition_wait_until();
371 }
372 
do_test_condition_wait_until_pred()373 void do_test_condition_wait_until_pred() {
374     test1 = 0;
375     test2 = 0;
376     runs = 0;
377 
378     boost::fibers::mutex m;
379     boost::fibers::condition_variable_any cv;
380     {
381         m.lock();
382         boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) );
383         BOOST_CHECK(test1 == 0);
384         while (test1 == 0)
385             cv.wait(m);
386         BOOST_CHECK(test1 != 0);
387         test2 = 1;
388         m.unlock();
389         cv.notify_one();
390         f.join();
391     }
392     test1 = 0;
393     test2 = 0;
394     {
395         m.lock();
396         boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( m), std::ref( cv) );
397         BOOST_CHECK(test1 == 0);
398         while (test1 == 0)
399             cv.wait(m);
400         BOOST_CHECK(test1 != 0);
401         m.unlock();
402         f.join();
403     }
404 }
405 
test_condition_wait_until_pred()406 void test_condition_wait_until_pred() {
407     boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until_pred).join();
408     do_test_condition_wait_until_pred();
409 }
410 
do_test_condition_wait_for()411 void do_test_condition_wait_for() {
412     test1 = 0;
413     test2 = 0;
414     runs = 0;
415 
416     boost::fibers::mutex m;
417     boost::fibers::condition_variable_any cv;
418     {
419         m.lock();
420         boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) );
421         BOOST_CHECK(test1 == 0);
422         while (test1 == 0)
423             cv.wait(m);
424         BOOST_CHECK(test1 != 0);
425         test2 = 1;
426         m.unlock();
427         cv.notify_one();
428         f.join();
429     }
430     test1 = 0;
431     test2 = 0;
432     {
433         m.lock();
434         boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( m), std::ref( cv) );
435         BOOST_CHECK(test1 == 0);
436         while (test1 == 0)
437             cv.wait(m);
438         BOOST_CHECK(test1 != 0);
439         m.unlock();
440         f.join();
441     }
442 }
443 
test_condition_wait_for()444 void test_condition_wait_for() {
445     boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for).join();
446     do_test_condition_wait_for();
447 }
448 
do_test_condition_wait_for_pred()449 void do_test_condition_wait_for_pred() {
450     test1 = 0;
451     test2 = 0;
452     runs = 0;
453 
454     boost::fibers::mutex m;
455     boost::fibers::condition_variable_any cv;
456     {
457         m.lock();
458         boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) );
459         BOOST_CHECK(test1 == 0);
460         while (test1 == 0)
461             cv.wait(m);
462         BOOST_CHECK(test1 != 0);
463         test2 = 1;
464         m.unlock();
465         cv.notify_one();
466         f.join();
467     }
468     test1 = 0;
469     test2 = 0;
470     {
471         m.lock();
472         boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( m), std::ref( cv) );
473         BOOST_CHECK(test1 == 0);
474         while (test1 == 0)
475             cv.wait(m);
476         BOOST_CHECK(test1 != 0);
477         m.unlock();
478         f.join();
479     }
480 }
481 
test_condition_wait_for_pred()482 void test_condition_wait_for_pred() {
483     boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for_pred).join();
484     do_test_condition_wait_for_pred();
485 }
486 
init_unit_test_suite(int,char * [])487 boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
488     boost::unit_test::test_suite * test =
489         BOOST_TEST_SUITE("Boost.Fiber: condition_variable_any test suite");
490 
491     test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) );
492     test->add( BOOST_TEST_CASE( & test_two_waiter_notify_one) );
493     test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) );
494     test->add( BOOST_TEST_CASE( & test_condition_wait) );
495     test->add( BOOST_TEST_CASE( & test_condition_wait_until) );
496     test->add( BOOST_TEST_CASE( & test_condition_wait_until_pred) );
497     test->add( BOOST_TEST_CASE( & test_condition_wait_for) );
498     test->add( BOOST_TEST_CASE( & test_condition_wait_for_pred) );
499 
500 	return test;
501 }
502