]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 | 25 | int value1 = 0; |
7c673cae FG |
26 | |
27 | inline | |
b32b8144 | 28 | std::chrono::system_clock::time_point delay(int secs, int msecs = 0, int /*nsecs*/ = 0) { |
7c673cae FG |
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 { | |
38 | 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 | ||
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 { | |
56 | cond_predicate(int& var, int val) : _var(var), _val(val) { } | |
57 | ||
58 | bool operator()() { return _var == _val; } | |
59 | ||
60 | int& _var; | |
61 | int _val; | |
62 | private: | |
63 | void operator=(cond_predicate&); | |
64 | ||
65 | }; | |
66 | ||
67 | void notify_one_fn( boost::fibers::condition_variable & cond) { | |
68 | cond.notify_one(); | |
69 | } | |
70 | ||
71 | void notify_all_fn( boost::fibers::condition_variable & cond) { | |
72 | cond.notify_all(); | |
73 | } | |
74 | ||
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); | |
b32b8144 | 80 | ++value1; |
7c673cae FG |
81 | } |
82 | ||
83 | void test_one_waiter_notify_one() { | |
b32b8144 | 84 | value1 = 0; |
7c673cae FG |
85 | boost::fibers::mutex mtx; |
86 | boost::fibers::condition_variable cond; | |
87 | ||
88 | boost::fibers::fiber f1( | |
89 | boost::fibers::launch::post, | |
90 | wait_fn, | |
91 | std::ref( mtx), | |
92 | std::ref( cond) ); | |
b32b8144 | 93 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
94 | |
95 | boost::fibers::fiber f2( | |
96 | boost::fibers::launch::post, | |
97 | notify_one_fn, | |
98 | std::ref( cond) ); | |
99 | ||
b32b8144 | 100 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
101 | |
102 | f1.join(); | |
103 | f2.join(); | |
104 | ||
b32b8144 | 105 | BOOST_CHECK_EQUAL( 1, value1); |
7c673cae FG |
106 | } |
107 | ||
108 | void test_two_waiter_notify_one() { | |
b32b8144 | 109 | value1 = 0; |
7c673cae FG |
110 | boost::fibers::mutex mtx; |
111 | boost::fibers::condition_variable cond; | |
112 | ||
113 | boost::fibers::fiber f1( | |
114 | boost::fibers::launch::post, | |
115 | wait_fn, | |
116 | std::ref( mtx), | |
117 | std::ref( cond) ); | |
b32b8144 | 118 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
119 | |
120 | boost::fibers::fiber f2( | |
121 | boost::fibers::launch::post, | |
122 | wait_fn, | |
123 | std::ref( mtx), | |
124 | std::ref( cond) ); | |
b32b8144 | 125 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
126 | |
127 | boost::fibers::fiber f3( | |
128 | boost::fibers::launch::post, | |
129 | notify_one_fn, | |
130 | std::ref( cond) ); | |
b32b8144 | 131 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
132 | |
133 | boost::fibers::fiber f4( | |
134 | boost::fibers::launch::post, | |
135 | notify_one_fn, | |
136 | std::ref( cond) ); | |
b32b8144 | 137 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
138 | |
139 | f1.join(); | |
140 | f2.join(); | |
141 | f3.join(); | |
142 | f4.join(); | |
143 | ||
b32b8144 | 144 | BOOST_CHECK_EQUAL( 2, value1); |
7c673cae FG |
145 | } |
146 | ||
147 | void test_two_waiter_notify_all() { | |
b32b8144 | 148 | value1 = 0; |
7c673cae FG |
149 | boost::fibers::mutex mtx; |
150 | boost::fibers::condition_variable cond; | |
151 | ||
152 | boost::fibers::fiber f1( | |
153 | boost::fibers::launch::post, | |
154 | wait_fn, | |
155 | std::ref( mtx), | |
156 | std::ref( cond) ); | |
b32b8144 | 157 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
158 | |
159 | boost::fibers::fiber f2( | |
160 | boost::fibers::launch::post, | |
161 | wait_fn, | |
162 | std::ref( mtx), | |
163 | std::ref( cond) ); | |
b32b8144 | 164 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
165 | |
166 | boost::fibers::fiber f3( | |
167 | boost::fibers::launch::post, | |
168 | notify_all_fn, | |
169 | std::ref( cond) ); | |
b32b8144 | 170 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
171 | |
172 | boost::fibers::fiber f4( | |
173 | boost::fibers::launch::post, | |
174 | wait_fn, | |
175 | std::ref( mtx), | |
176 | std::ref( cond) ); | |
b32b8144 | 177 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
178 | |
179 | boost::fibers::fiber f5( | |
180 | boost::fibers::launch::post, | |
181 | notify_all_fn, | |
182 | std::ref( cond) ); | |
b32b8144 | 183 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
184 | |
185 | f1.join(); | |
186 | f2.join(); | |
187 | f3.join(); | |
188 | f4.join(); | |
189 | f5.join(); | |
190 | ||
b32b8144 | 191 | BOOST_CHECK_EQUAL( 3, value1); |
7c673cae FG |
192 | } |
193 | ||
194 | int test1 = 0; | |
195 | int test2 = 0; | |
196 | ||
197 | int runs = 0; | |
198 | ||
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 | ||
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 { | |
b32b8144 | 225 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); |
7c673cae FG |
226 | BOOST_CHECK(test2 == 0); |
227 | } | |
228 | ++runs; | |
229 | } | |
230 | ||
231 | class Pred { | |
232 | int & i_; | |
233 | ||
234 | public: | |
235 | explicit Pred(int& i) : | |
236 | i_(i) | |
237 | {} | |
238 | ||
239 | bool operator()() | |
240 | { return i_ != 0; } | |
241 | }; | |
242 | ||
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 { | |
b32b8144 | 257 | BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); |
7c673cae FG |
258 | BOOST_CHECK(test2 == 0); |
259 | BOOST_CHECK(!r); | |
260 | } | |
261 | ++runs; | |
262 | } | |
263 | ||
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 { | |
b32b8144 | 278 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); |
7c673cae FG |
279 | BOOST_CHECK(test2 == 0); |
280 | } | |
281 | ++runs; | |
282 | } | |
283 | ||
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 { | |
b32b8144 | 298 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); |
7c673cae FG |
299 | BOOST_CHECK(test2 == 0); |
300 | } | |
301 | ++runs; | |
302 | } | |
303 | ||
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::post, & 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 | ||
323 | void test_condition_wait() { | |
324 | boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait).join(); | |
325 | do_test_condition_wait(); | |
326 | } | |
327 | ||
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::post, & 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::post, & 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 | ||
361 | void test_condition_wait_until() { | |
362 | boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until).join(); | |
363 | do_test_condition_wait_until(); | |
364 | } | |
365 | ||
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::post, & 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::post, & 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 | ||
399 | void test_condition_wait_until_pred() { | |
400 | boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_until_pred).join(); | |
401 | do_test_condition_wait_until_pred(); | |
402 | } | |
403 | ||
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::post, & 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::post, & 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 | ||
437 | void test_condition_wait_for() { | |
438 | boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for).join(); | |
439 | do_test_condition_wait_for(); | |
440 | } | |
441 | ||
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::post, & 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::post, & 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 | ||
475 | void test_condition_wait_for_pred() { | |
476 | boost::fibers::fiber( boost::fibers::launch::post, & do_test_condition_wait_for_pred).join(); | |
477 | do_test_condition_wait_for_pred(); | |
478 | } | |
479 | ||
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 | } |