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 <iostream>
12 #include <map>
13 #include <mutex>
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 int value2 = 0;
26
27 template< typename M >
fn1(M & mtx)28 void fn1( M & mtx) {
29 typedef M mutex_type;
30 typename std::unique_lock< mutex_type > lk( mtx);
31 ++value1;
32 for ( int i = 0; i < 3; ++i)
33 boost::this_fiber::yield();
34 }
35
36 template< typename M >
fn2(M & mtx)37 void fn2( M & mtx) {
38 typedef M mutex_type;
39 ++value2;
40 typename std::unique_lock< mutex_type > lk( mtx);
41 ++value2;
42 }
43
fn3(boost::fibers::timed_mutex & m)44 void fn3( boost::fibers::timed_mutex & m) {
45 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
46 m.lock();
47 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
48 m.unlock();
49 ns d = t1 - t0 - ms(250);
50 BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
51 }
52
fn4(boost::fibers::timed_mutex & m)53 void fn4( boost::fibers::timed_mutex & m) {
54 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
55 while ( ! m.try_lock() );
56 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
57 m.unlock();
58 ns d = t1 - t0 - ms(250);
59 BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
60 }
61
fn5(boost::fibers::timed_mutex & m)62 void fn5( boost::fibers::timed_mutex & m) {
63 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
64 BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true);
65 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
66 m.unlock();
67 ns d = t1 - t0 - ms(250);
68 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
69 }
70
fn6(boost::fibers::timed_mutex & m)71 void fn6( boost::fibers::timed_mutex & m) {
72 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
73 BOOST_CHECK(m.try_lock_for(ms(250)) == false);
74 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
75 ns d = t1 - t0 - ms(250);
76 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
77 }
78
fn7(boost::fibers::timed_mutex & m)79 void fn7( boost::fibers::timed_mutex & m) {
80 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
81 BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
82 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
83 m.unlock();
84 ns d = t1 - t0 - ms(250);
85 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms
86 }
87
fn8(boost::fibers::timed_mutex & m)88 void fn8( boost::fibers::timed_mutex & m) {
89 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
90 BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
91 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
92 ns d = t1 - t0 - ms(250);
93 ns r = ns(5000000)+ms(2000); // within 6ms
94 BOOST_CHECK(d < r); // within 6ms
95 }
96
fn9(boost::fibers::recursive_timed_mutex & m)97 void fn9( boost::fibers::recursive_timed_mutex & m) {
98 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
99 m.lock();
100 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
101 m.lock();
102 m.unlock();
103 m.unlock();
104 ns d = t1 - t0 - ms(250);
105 BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms
106 }
107
fn10(boost::fibers::recursive_timed_mutex & m)108 void fn10( boost::fibers::recursive_timed_mutex & m) {
109 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
110 while (!m.try_lock()) ;
111 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
112 BOOST_CHECK(m.try_lock());
113 m.unlock();
114 m.unlock();
115 ns d = t1 - t0 - ms(250);
116 BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
117 }
118
fn11(boost::fibers::recursive_timed_mutex & m)119 void fn11( boost::fibers::recursive_timed_mutex & m) {
120 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
121 BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true);
122 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
123 BOOST_CHECK(m.try_lock());
124 m.unlock();
125 m.unlock();
126 ns d = t1 - t0 - ms(250);
127 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
128 }
129
fn12(boost::fibers::recursive_timed_mutex & m)130 void fn12( boost::fibers::recursive_timed_mutex & m) {
131 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
132 BOOST_CHECK(m.try_lock_for(ms(250)) == false);
133 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
134 ns d = t1 - t0 - ms(250);
135 BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms
136 }
137
fn13(boost::fibers::recursive_timed_mutex & m)138 void fn13( boost::fibers::recursive_timed_mutex & m) {
139 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
140 BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
141 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
142 m.unlock();
143 ns d = t1 - t0 - ms(250);
144 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
145 }
146
fn14(boost::fibers::recursive_timed_mutex & m)147 void fn14( boost::fibers::recursive_timed_mutex & m) {
148 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
149 BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
150 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
151 ns d = t1 - t0 - ms(250);
152 BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
153 }
154
fn15(boost::fibers::recursive_mutex & m)155 void fn15( boost::fibers::recursive_mutex & m) {
156 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
157 m.lock();
158 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
159 m.lock();
160 m.unlock();
161 m.unlock();
162 ns d = t1 - t0 - ms(250);
163 BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
164 }
165
fn16(boost::fibers::recursive_mutex & m)166 void fn16( boost::fibers::recursive_mutex & m) {
167 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
168 while (!m.try_lock());
169 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
170 BOOST_CHECK(m.try_lock());
171 m.unlock();
172 m.unlock();
173 ns d = t1 - t0 - ms(250);
174 BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
175 }
176
fn17(boost::fibers::mutex & m)177 void fn17( boost::fibers::mutex & m) {
178 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
179 m.lock();
180 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
181 m.unlock();
182 ns d = t1 - t0 - ms(250);
183 BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
184 }
185
fn18(boost::fibers::mutex & m)186 void fn18( boost::fibers::mutex & m) {
187 std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
188 while (!m.try_lock()) ;
189 std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
190 m.unlock();
191 ns d = t1 - t0 - ms(250);
192 BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
193 }
194
195 template< typename M >
196 struct test_lock {
197 typedef M mutex_type;
198 typedef typename std::unique_lock< M > lock_type;
199
operator ()test_lock200 void operator()() {
201 mutex_type mtx;
202
203 // Test the lock's constructors.
204 {
205 lock_type lk(mtx, std::defer_lock);
206 BOOST_CHECK(!lk);
207 }
208 lock_type lk(mtx);
209 BOOST_CHECK(lk ? true : false);
210
211 // Test the lock and unlock methods.
212 lk.unlock();
213 BOOST_CHECK(!lk);
214 lk.lock();
215 BOOST_CHECK(lk ? true : false);
216 }
217 };
218
219 template< typename M >
220 struct test_exclusive {
221 typedef M mutex_type;
222 typedef typename std::unique_lock< M > lock_type;
223
operator ()test_exclusive224 void operator()() {
225 value1 = 0;
226 value2 = 0;
227 BOOST_CHECK_EQUAL( 0, value1);
228 BOOST_CHECK_EQUAL( 0, value2);
229
230 mutex_type mtx;
231 boost::fibers::fiber f1( boost::fibers::launch::post, & fn1< mutex_type >, std::ref( mtx) );
232 boost::fibers::fiber f2( boost::fibers::launch::post, & fn2< mutex_type >, std::ref( mtx) );
233 BOOST_ASSERT( f1.joinable() );
234 BOOST_ASSERT( f2.joinable() );
235
236 f1.join();
237 f2.join();
238 BOOST_CHECK_EQUAL( 1, value1);
239 BOOST_CHECK_EQUAL( 2, value2);
240 }
241 };
242
243 template< typename M >
244 struct test_recursive_lock {
245 typedef M mutex_type;
246 typedef typename std::unique_lock< M > lock_type;
247
operator ()test_recursive_lock248 void operator()() {
249 mutex_type mx;
250 lock_type lock1(mx);
251 lock_type lock2(mx);
252 }
253 };
254
do_test_mutex()255 void do_test_mutex() {
256 test_lock< boost::fibers::mutex >()();
257 test_exclusive< boost::fibers::mutex >()();
258
259 {
260 boost::fibers::mutex mtx;
261 mtx.lock();
262 boost::fibers::fiber f( boost::fibers::launch::post, & fn17, std::ref( mtx) );
263 boost::this_fiber::sleep_for( ms(250) );
264 mtx.unlock();
265 f.join();
266 }
267
268 {
269 boost::fibers::mutex mtx;
270 mtx.lock();
271 boost::fibers::fiber f( boost::fibers::launch::post, & fn18, std::ref( mtx) );
272 boost::this_fiber::sleep_for( ms(250) );
273 mtx.unlock();
274 f.join();
275 }
276 }
277
test_mutex()278 void test_mutex() {
279 boost::fibers::fiber( boost::fibers::launch::post, & do_test_mutex).join();
280 }
281
do_test_recursive_mutex()282 void do_test_recursive_mutex() {
283 test_lock< boost::fibers::recursive_mutex >()();
284 test_exclusive< boost::fibers::recursive_mutex >()();
285 test_recursive_lock< boost::fibers::recursive_mutex >()();
286
287 {
288 boost::fibers::recursive_mutex mtx;
289 mtx.lock();
290 boost::fibers::fiber f( boost::fibers::launch::post, & fn15, std::ref( mtx) );
291 boost::this_fiber::sleep_for( ms(250) );
292 mtx.unlock();
293 f.join();
294 }
295
296 {
297 boost::fibers::recursive_mutex mtx;
298 mtx.lock();
299 boost::fibers::fiber f( boost::fibers::launch::post, & fn16, std::ref( mtx) );
300 boost::this_fiber::sleep_for( ms(250) );
301 mtx.unlock();
302 f.join();
303 }
304 }
305
test_recursive_mutex()306 void test_recursive_mutex() {
307 boost::fibers::fiber( boost::fibers::launch::post, do_test_recursive_mutex).join();
308 }
309
do_test_timed_mutex()310 void do_test_timed_mutex() {
311 test_lock< boost::fibers::timed_mutex >()();
312 test_exclusive< boost::fibers::timed_mutex >()();
313
314 {
315 boost::fibers::timed_mutex timed_mtx;
316 timed_mtx.lock();
317 boost::fibers::fiber f( boost::fibers::launch::post, & fn3, std::ref( timed_mtx) );
318 boost::this_fiber::sleep_for( ms(250) );
319 timed_mtx.unlock();
320 f.join();
321 }
322
323 {
324 boost::fibers::timed_mutex timed_mtx;
325 timed_mtx.lock();
326 boost::fibers::fiber f( boost::fibers::launch::post, & fn4, std::ref( timed_mtx) );
327 boost::this_fiber::sleep_for( ms(250) );
328 timed_mtx.unlock();
329 f.join();
330 }
331
332 {
333 boost::fibers::timed_mutex timed_mtx;
334 timed_mtx.lock();
335 boost::fibers::fiber f( boost::fibers::launch::post, & fn5, std::ref( timed_mtx) );
336 boost::this_fiber::sleep_for( ms(250) );
337 timed_mtx.unlock();
338 f.join();
339 }
340
341 {
342 boost::fibers::timed_mutex timed_mtx;
343 timed_mtx.lock();
344 boost::fibers::fiber f( boost::fibers::launch::post, & fn6, std::ref( timed_mtx) );
345 boost::this_fiber::sleep_for( ms(300) );
346 timed_mtx.unlock();
347 f.join();
348 }
349
350 {
351 boost::fibers::timed_mutex timed_mtx;
352 timed_mtx.lock();
353 boost::fibers::fiber f( boost::fibers::launch::post, & fn7, std::ref( timed_mtx) );
354 boost::this_fiber::sleep_for( ms(250) );
355 timed_mtx.unlock();
356 f.join();
357 }
358
359 {
360 boost::fibers::timed_mutex timed_mtx;
361 timed_mtx.lock();
362 boost::fibers::fiber f( boost::fibers::launch::post, & fn8, std::ref( timed_mtx) );
363 boost::this_fiber::sleep_for( ms(300) + ms(1000) );
364 timed_mtx.unlock();
365 f.join();
366 }
367 }
368
test_timed_mutex()369 void test_timed_mutex() {
370 boost::fibers::fiber( boost::fibers::launch::post, & do_test_timed_mutex).join();
371 }
372
do_test_recursive_timed_mutex()373 void do_test_recursive_timed_mutex() {
374 test_lock< boost::fibers::recursive_timed_mutex >()();
375 test_exclusive< boost::fibers::recursive_timed_mutex >()();
376 test_recursive_lock< boost::fibers::recursive_timed_mutex >()();
377
378 {
379 boost::fibers::recursive_timed_mutex timed_mtx;
380 timed_mtx.lock();
381 boost::fibers::fiber f( boost::fibers::launch::post, & fn9, std::ref( timed_mtx) );
382 boost::this_fiber::sleep_for( ms(250) );
383 timed_mtx.unlock();
384 f.join();
385 }
386
387 {
388 boost::fibers::recursive_timed_mutex timed_mtx;
389 timed_mtx.lock();
390 boost::fibers::fiber f( boost::fibers::launch::post, & fn10, std::ref( timed_mtx) );
391 boost::this_fiber::sleep_for( ms(250) );
392 timed_mtx.unlock();
393 f.join();
394 }
395
396 {
397 boost::fibers::recursive_timed_mutex timed_mtx;
398 timed_mtx.lock();
399 boost::fibers::fiber f( boost::fibers::launch::post, & fn11, std::ref( timed_mtx) );
400 boost::this_fiber::sleep_for( ms(250) );
401 timed_mtx.unlock();
402 f.join();
403 }
404
405 {
406 boost::fibers::recursive_timed_mutex timed_mtx;
407 timed_mtx.lock();
408 boost::fibers::fiber f( boost::fibers::launch::post, & fn12, std::ref( timed_mtx) );
409 boost::this_fiber::sleep_for( ms(400) );
410 timed_mtx.unlock();
411 f.join();
412 }
413
414 {
415 boost::fibers::recursive_timed_mutex timed_mtx;
416 timed_mtx.lock();
417 boost::fibers::fiber f( boost::fibers::launch::post, & fn13, std::ref( timed_mtx) );
418 boost::this_fiber::sleep_for( ms(250) );
419 timed_mtx.unlock();
420 f.join();
421 }
422
423 {
424 boost::fibers::recursive_timed_mutex timed_mtx;
425 timed_mtx.lock();
426 boost::fibers::fiber f( boost::fibers::launch::post, & fn14, std::ref( timed_mtx) );
427 boost::this_fiber::sleep_for( ms(300) );
428 timed_mtx.unlock();
429 f.join();
430 }
431 }
432
test_recursive_timed_mutex()433 void test_recursive_timed_mutex() {
434 boost::fibers::fiber( boost::fibers::launch::post, & do_test_recursive_timed_mutex).join();
435 }
436
init_unit_test_suite(int,char * [])437 boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
438 boost::unit_test::test_suite * test =
439 BOOST_TEST_SUITE("Boost.Fiber: mutex test suite");
440
441 test->add( BOOST_TEST_CASE( & test_mutex) );
442 test->add( BOOST_TEST_CASE( & test_recursive_mutex) );
443 test->add( BOOST_TEST_CASE( & test_timed_mutex) );
444 test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) );
445
446 return test;
447 }
448