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