]>
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 <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 | ||
b32b8144 | 24 | int value1 = 0; |
7c673cae FG |
25 | |
26 | inline | |
b32b8144 | 27 | std::chrono::system_clock::time_point delay(int secs, int msecs=0, int /*nsecs*/=0) { |
7c673cae FG |
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 { | |
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 | ||
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 { | |
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; | |
63 | private: | |
64 | void operator=(cond_predicate&); | |
65 | ||
66 | }; | |
67 | ||
68 | void notify_one_fn( boost::fibers::condition_variable_any & cond) { | |
69 | cond.notify_one(); | |
70 | } | |
71 | ||
72 | void notify_all_fn( boost::fibers::condition_variable_any & cond) { | |
73 | cond.notify_all(); | |
74 | } | |
75 | ||
76 | void wait_fn( | |
77 | boost::fibers::mutex & mtx, | |
78 | boost::fibers::condition_variable_any & cond) { | |
79 | mtx.lock(); | |
80 | cond.wait( mtx); | |
b32b8144 | 81 | ++value1; |
7c673cae FG |
82 | mtx.unlock(); |
83 | } | |
84 | ||
85 | void test_one_waiter_notify_one() { | |
b32b8144 | 86 | value1 = 0; |
7c673cae FG |
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) ); | |
b32b8144 | 95 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
96 | |
97 | boost::fibers::fiber f2( | |
98 | boost::fibers::launch::post, | |
99 | notify_one_fn, | |
100 | std::ref( cond) ); | |
101 | ||
b32b8144 | 102 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
103 | |
104 | f1.join(); | |
105 | f2.join(); | |
106 | ||
b32b8144 | 107 | BOOST_CHECK_EQUAL( 1, value1); |
7c673cae FG |
108 | } |
109 | ||
110 | void test_two_waiter_notify_one() { | |
b32b8144 | 111 | value1 = 0; |
7c673cae FG |
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) ); | |
b32b8144 | 120 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
121 | |
122 | boost::fibers::fiber f2( | |
123 | boost::fibers::launch::post, | |
124 | wait_fn, | |
125 | std::ref( mtx), | |
126 | std::ref( cond) ); | |
b32b8144 | 127 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
128 | |
129 | boost::fibers::fiber f3( | |
130 | boost::fibers::launch::post, | |
131 | notify_one_fn, | |
132 | std::ref( cond) ); | |
b32b8144 | 133 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
134 | |
135 | boost::fibers::fiber f4( | |
136 | boost::fibers::launch::post, | |
137 | notify_one_fn, | |
138 | std::ref( cond) ); | |
b32b8144 | 139 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
140 | |
141 | f1.join(); | |
142 | f2.join(); | |
143 | f3.join(); | |
144 | f4.join(); | |
145 | ||
b32b8144 | 146 | BOOST_CHECK_EQUAL( 2, value1); |
7c673cae FG |
147 | } |
148 | ||
149 | void test_two_waiter_notify_all() { | |
b32b8144 | 150 | value1 = 0; |
7c673cae FG |
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) ); | |
b32b8144 | 159 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
160 | |
161 | boost::fibers::fiber f2( | |
162 | boost::fibers::launch::post, | |
163 | wait_fn, | |
164 | std::ref( mtx), | |
165 | std::ref( cond) ); | |
b32b8144 | 166 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
167 | |
168 | boost::fibers::fiber f3( | |
169 | boost::fibers::launch::post, | |
170 | notify_all_fn, | |
171 | std::ref( cond) ); | |
b32b8144 | 172 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
173 | |
174 | boost::fibers::fiber f4( | |
175 | boost::fibers::launch::post, | |
176 | wait_fn, | |
177 | std::ref( mtx), | |
178 | std::ref( cond) ); | |
b32b8144 | 179 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
180 | |
181 | boost::fibers::fiber f5( | |
182 | boost::fibers::launch::post, | |
183 | notify_all_fn, | |
184 | std::ref( cond) ); | |
b32b8144 | 185 | BOOST_CHECK_EQUAL( 0, value1); |
7c673cae FG |
186 | |
187 | f1.join(); | |
188 | f2.join(); | |
189 | f3.join(); | |
190 | f4.join(); | |
191 | f5.join(); | |
192 | ||
b32b8144 | 193 | BOOST_CHECK_EQUAL( 3, value1); |
7c673cae FG |
194 | } |
195 | ||
196 | int test1 = 0; | |
197 | int test2 = 0; | |
198 | ||
199 | int runs = 0; | |
200 | ||
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 | ||
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 { | |
b32b8144 | 228 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); |
7c673cae FG |
229 | BOOST_CHECK(test2 == 0); |
230 | } | |
231 | ++runs; | |
232 | m.unlock(); | |
233 | } | |
234 | ||
235 | class Pred { | |
236 | int & i_; | |
237 | ||
238 | public: | |
239 | explicit Pred(int& i) : | |
240 | i_(i) | |
241 | {} | |
242 | ||
243 | bool operator()() | |
244 | { return i_ != 0; } | |
245 | }; | |
246 | ||
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 { | |
b32b8144 | 261 | BOOST_CHECK(t1 - t0 - ms(250) < ms(250+100)); |
7c673cae FG |
262 | BOOST_CHECK(test2 == 0); |
263 | BOOST_CHECK(!r); | |
264 | } | |
265 | ++runs; | |
266 | m.unlock(); | |
267 | } | |
268 | ||
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 { | |
b32b8144 | 283 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100+1000)); |
7c673cae FG |
284 | BOOST_CHECK(test2 == 0); |
285 | } | |
286 | ++runs; | |
287 | m.unlock(); | |
288 | } | |
289 | ||
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 { | |
b32b8144 | 304 | BOOST_CHECK(t1 - t0 - ms(250) < ms(count*250+100)); |
7c673cae FG |
305 | BOOST_CHECK(test2 == 0); |
306 | } | |
307 | ++runs; | |
308 | m.unlock(); | |
309 | } | |
310 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | } |