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
21typedef std::chrono::nanoseconds ns;
22typedef std::chrono::milliseconds ms;
23
24int value1 = 0;
25
26inline
27std::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
36struct condition_test_data {
37 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
45void condition_test_fiber(condition_test_data* data) {
46 try {
47 data->mutex.lock();
48 while (!(data->notified > 0))
49 data->cond.wait(lt&: data->mutex);
50 data->awoken++;
51 } catch ( ... ) {
52 }
53 data->mutex.unlock();
54}
55
56struct cond_predicate {
57 cond_predicate(int& var, int val) : _var(var), _val(val) { }
58
59 bool operator()() { return _var == _val; }
60
61 int& _var;
62 int _val;
63private:
64 void operator=(cond_predicate&);
65
66};
67
68void notify_one_fn( boost::fibers::condition_variable_any & cond) {
69 cond.notify_one();
70}
71
72void notify_all_fn( boost::fibers::condition_variable_any & cond) {
73 cond.notify_all();
74}
75
76void wait_fn(
77 boost::fibers::mutex & mtx,
78 boost::fibers::condition_variable_any & cond) {
79 mtx.lock();
80 cond.wait( lt&: mtx);
81 ++value1;
82 mtx.unlock();
83}
84
85void 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::dispatch,
92 wait_fn,
93 std::ref( t&: mtx),
94 std::ref( t&: cond) );
95 BOOST_CHECK_EQUAL( 0, value1);
96
97 boost::fibers::fiber f2(
98 boost::fibers::launch::dispatch,
99 notify_one_fn,
100 std::ref( t&: cond) );
101
102 BOOST_CHECK_EQUAL( 0, value1);
103
104 f1.join();
105 f2.join();
106
107 BOOST_CHECK_EQUAL( 1, value1);
108}
109
110void 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::dispatch,
117 wait_fn,
118 std::ref( t&: mtx),
119 std::ref( t&: cond) );
120 BOOST_CHECK_EQUAL( 0, value1);
121
122 boost::fibers::fiber f2(
123 boost::fibers::launch::dispatch,
124 wait_fn,
125 std::ref( t&: mtx),
126 std::ref( t&: cond) );
127 BOOST_CHECK_EQUAL( 0, value1);
128
129 boost::fibers::fiber f3(
130 boost::fibers::launch::dispatch,
131 notify_one_fn,
132 std::ref( t&: cond) );
133 BOOST_CHECK_EQUAL( 0, value1);
134
135 boost::fibers::fiber f4(
136 boost::fibers::launch::dispatch,
137 notify_one_fn,
138 std::ref( t&: cond) );
139 BOOST_CHECK_EQUAL( 1, value1);
140
141 f1.join();
142 f2.join();
143 f3.join();
144 f4.join();
145
146 BOOST_CHECK_EQUAL( 2, value1);
147}
148
149void 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::dispatch,
156 wait_fn,
157 std::ref( t&: mtx),
158 std::ref( t&: cond) );
159 BOOST_CHECK_EQUAL( 0, value1);
160
161 boost::fibers::fiber f2(
162 boost::fibers::launch::dispatch,
163 wait_fn,
164 std::ref( t&: mtx),
165 std::ref( t&: cond) );
166 BOOST_CHECK_EQUAL( 0, value1);
167
168 boost::fibers::fiber f3(
169 boost::fibers::launch::dispatch,
170 notify_all_fn,
171 std::ref( t&: cond) );
172 BOOST_CHECK_EQUAL( 0, value1);
173
174 boost::fibers::fiber f4(
175 boost::fibers::launch::dispatch,
176 wait_fn,
177 std::ref( t&: mtx),
178 std::ref( t&: cond) );
179 BOOST_CHECK_EQUAL( 2, value1);
180
181 boost::fibers::fiber f5(
182 boost::fibers::launch::dispatch,
183 notify_all_fn,
184 std::ref( t&: cond) );
185 BOOST_CHECK_EQUAL( 2, 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
196int test1 = 0;
197int test2 = 0;
198
199int runs = 0;
200
201void 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(lt&: m);
208 }
209 BOOST_CHECK(test2 != 0);
210 m.unlock();
211}
212
213void 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(lt&: m, timeout_time_: 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
235class Pred {
236 int & i_;
237
238public:
239 explicit Pred(int& i) :
240 i_(i)
241 {}
242
243 bool operator()()
244 { return i_ != 0; }
245};
246
247void 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(lt&: m, timeout_time: t, pred: 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
269void 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(lt&: m, timeout_duration: 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
290void 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(lt&: m, timeout_duration: ms(250), pred: 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
311void 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::dispatch, & fn1, std::ref( t&: m), std::ref( t&: cv) );
320 BOOST_CHECK(test1 == 0);
321 while (test1 == 0)
322 cv.wait(lt&: m);
323 BOOST_CHECK(test1 != 0);
324 test2 = 1;
325 m.unlock();
326 cv.notify_one();
327 f.join();
328}
329
330void test_condition_wait() {
331 boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait).join();
332 do_test_condition_wait();
333}
334
335void 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::dispatch, & fn2, std::ref( t&: m), std::ref( t&: cv) );
345 BOOST_CHECK(test1 == 0);
346 while (test1 == 0)
347 cv.wait(lt&: 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::dispatch, & fn2, std::ref( t&: m), std::ref( t&: cv) );
359 BOOST_CHECK(test1 == 0);
360 while (test1 == 0)
361 cv.wait(lt&: m);
362 BOOST_CHECK(test1 != 0);
363 m.unlock();
364 f.join();
365 }
366}
367
368void test_condition_wait_until() {
369 boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until).join();
370 do_test_condition_wait_until();
371}
372
373void 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::dispatch, & fn3, std::ref( t&: m), std::ref( t&: cv) );
383 BOOST_CHECK(test1 == 0);
384 while (test1 == 0)
385 cv.wait(lt&: 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::dispatch, & fn3, std::ref( t&: m), std::ref( t&: cv) );
397 BOOST_CHECK(test1 == 0);
398 while (test1 == 0)
399 cv.wait(lt&: m);
400 BOOST_CHECK(test1 != 0);
401 m.unlock();
402 f.join();
403 }
404}
405
406void test_condition_wait_until_pred() {
407 boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_until_pred).join();
408 do_test_condition_wait_until_pred();
409}
410
411void 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::dispatch, & fn4, std::ref( t&: m), std::ref( t&: cv) );
421 BOOST_CHECK(test1 == 0);
422 while (test1 == 0)
423 cv.wait(lt&: 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::dispatch, & fn4, std::ref( t&: m), std::ref( t&: cv) );
435 BOOST_CHECK(test1 == 0);
436 while (test1 == 0)
437 cv.wait(lt&: m);
438 BOOST_CHECK(test1 != 0);
439 m.unlock();
440 f.join();
441 }
442}
443
444void test_condition_wait_for() {
445 boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for).join();
446 do_test_condition_wait_for();
447}
448
449void 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::dispatch, & fn5, std::ref( t&: m), std::ref( t&: cv) );
459 BOOST_CHECK(test1 == 0);
460 while (test1 == 0)
461 cv.wait(lt&: 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::dispatch, & fn5, std::ref( t&: m), std::ref( t&: cv) );
473 BOOST_CHECK(test1 == 0);
474 while (test1 == 0)
475 cv.wait(lt&: m);
476 BOOST_CHECK(test1 != 0);
477 m.unlock();
478 f.join();
479 }
480}
481
482void test_condition_wait_for_pred() {
483 boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_condition_wait_for_pred).join();
484 do_test_condition_wait_for_pred();
485}
486
487boost::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

source code of boost/libs/fiber/test/test_condition_variable_any_dispatch.cpp