• 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 <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