]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/test/test_generic_locks.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / thread / test / test_generic_locks.cpp
1 // (C) Copyright 2008 Anthony Williams
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 #define BOOST_THREAD_VERSION 2
7
8 #define BOOST_TEST_MODULE Boost.Threads: generic locks test suite
9
10 #include <boost/test/unit_test.hpp>
11 #include <boost/thread/mutex.hpp>
12 #include <boost/thread/thread_only.hpp>
13 #include <boost/thread/locks.hpp>
14 #include <boost/thread/condition_variable.hpp>
15
16 BOOST_AUTO_TEST_CASE(test_lock_two_uncontended)
17 {
18 boost::mutex m1,m2;
19
20 boost::unique_lock<boost::mutex> l1(m1,boost::defer_lock),
21 l2(m2,boost::defer_lock);
22
23 BOOST_CHECK(!l1.owns_lock());
24 BOOST_CHECK(!l2.owns_lock());
25
26 boost::lock(l1,l2);
27
28 BOOST_CHECK(l1.owns_lock());
29 BOOST_CHECK(l2.owns_lock());
30 }
31
32 struct wait_data
33 {
34 boost::mutex m;
35 bool flag;
36 boost::condition_variable cond;
37
38 wait_data():
39 flag(false)
40 {}
41
42 void wait()
43 {
44 boost::unique_lock<boost::mutex> l(m);
45 while(!flag)
46 {
47 cond.wait(l);
48 }
49 }
50
51 template<typename Duration>
52 bool timed_wait(Duration d)
53 {
54 boost::system_time const target=boost::get_system_time()+d;
55
56 boost::unique_lock<boost::mutex> l(m);
57 while(!flag)
58 {
59 if(!cond.timed_wait(l,target))
60 {
61 return flag;
62 }
63 }
64 return true;
65 }
66
67 void signal()
68 {
69 boost::unique_lock<boost::mutex> l(m);
70 flag=true;
71 cond.notify_all();
72 }
73 };
74
75
76 void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
77 {
78 boost::lock_guard<boost::mutex> l1(*m1);
79 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
80 boost::lock_guard<boost::mutex> l2(*m2);
81 locked->signal();
82 quit->wait();
83 }
84
85 void lock_pair(boost::mutex* m1,boost::mutex* m2)
86 {
87 boost::lock(*m1,*m2);
88 boost::unique_lock<boost::mutex> l1(*m1,boost::adopt_lock),
89 l2(*m2,boost::adopt_lock);
90 }
91
92 BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_order)
93 {
94 boost::mutex m1,m2;
95 wait_data locked;
96 wait_data release;
97
98 boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
99 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
100
101 boost::thread t2(lock_pair,&m1,&m2);
102 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
103
104 release.signal();
105
106 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
107
108 t.join();
109 }
110
111 BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_opposite_order)
112 {
113 boost::mutex m1,m2;
114 wait_data locked;
115 wait_data release;
116
117 boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
118 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
119
120 boost::thread t2(lock_pair,&m2,&m1);
121 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
122
123 release.signal();
124
125 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
126
127 t.join();
128 }
129
130 BOOST_AUTO_TEST_CASE(test_lock_five_uncontended)
131 {
132 boost::mutex m1,m2,m3,m4,m5;
133
134 boost::unique_lock<boost::mutex> l1(m1,boost::defer_lock),
135 l2(m2,boost::defer_lock),
136 l3(m3,boost::defer_lock),
137 l4(m4,boost::defer_lock),
138 l5(m5,boost::defer_lock);
139
140 BOOST_CHECK(!l1.owns_lock());
141 BOOST_CHECK(!l2.owns_lock());
142 BOOST_CHECK(!l3.owns_lock());
143 BOOST_CHECK(!l4.owns_lock());
144 BOOST_CHECK(!l5.owns_lock());
145
146 boost::lock(l1,l2,l3,l4,l5);
147
148 BOOST_CHECK(l1.owns_lock());
149 BOOST_CHECK(l2.owns_lock());
150 BOOST_CHECK(l3.owns_lock());
151 BOOST_CHECK(l4.owns_lock());
152 BOOST_CHECK(l5.owns_lock());
153 }
154
155 void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
156 wait_data* locked,wait_data* quit)
157 {
158 boost::lock_guard<boost::mutex> l1(*m1);
159 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
160 boost::lock_guard<boost::mutex> l2(*m2);
161 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
162 boost::lock_guard<boost::mutex> l3(*m3);
163 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
164 boost::lock_guard<boost::mutex> l4(*m4);
165 boost::this_thread::sleep(boost::posix_time::milliseconds(500));
166 boost::lock_guard<boost::mutex> l5(*m5);
167 locked->signal();
168 quit->wait();
169 }
170
171 void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
172 {
173 boost::lock(*m1,*m2,*m3,*m4,*m5);
174 m1->unlock();
175 m2->unlock();
176 m3->unlock();
177 m4->unlock();
178 m5->unlock();
179 }
180
181 BOOST_AUTO_TEST_CASE(test_lock_five_other_thread_locks_in_order)
182 {
183 boost::mutex m1,m2,m3,m4,m5;
184 wait_data locked;
185 wait_data release;
186
187 boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
188 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
189
190 boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
191 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
192
193 release.signal();
194
195 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
196
197 t.join();
198 }
199
200 BOOST_AUTO_TEST_CASE(test_lock_five_other_thread_locks_in_different_order)
201 {
202 boost::mutex m1,m2,m3,m4,m5;
203 wait_data locked;
204 wait_data release;
205
206 boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
207 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
208
209 boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
210 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
211
212 release.signal();
213
214 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
215
216 t.join();
217 }
218
219 void lock_n(boost::mutex* mutexes,unsigned count)
220 {
221 boost::lock(mutexes,mutexes+count);
222 for(unsigned i=0;i<count;++i)
223 {
224 mutexes[i].unlock();
225 }
226 }
227
228
229 BOOST_AUTO_TEST_CASE(test_lock_ten_other_thread_locks_in_different_order)
230 {
231 unsigned const num_mutexes=10;
232
233 boost::mutex mutexes[num_mutexes];
234 wait_data locked;
235 wait_data release;
236
237 boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
238 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
239
240 boost::thread t2(lock_n,mutexes,num_mutexes);
241 BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
242
243 release.signal();
244
245 BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
246
247 t.join();
248 }
249
250 struct dummy_mutex
251 {
252 bool is_locked;
253
254 dummy_mutex():
255 is_locked(false)
256 {}
257
258 void lock()
259 {
260 is_locked=true;
261 }
262
263 bool try_lock()
264 {
265 if(is_locked)
266 {
267 return false;
268 }
269 is_locked=true;
270 return true;
271 }
272
273 void unlock()
274 {
275 is_locked=false;
276 }
277 };
278
279 namespace boost
280 {
281 template<>
282 struct is_mutex_type<dummy_mutex>
283 {
284 BOOST_STATIC_CONSTANT(bool, value = true);
285 };
286 }
287
288
289
290 BOOST_AUTO_TEST_CASE(test_lock_five_in_range)
291 {
292 unsigned const num_mutexes=5;
293 dummy_mutex mutexes[num_mutexes];
294
295 boost::lock(mutexes,mutexes+num_mutexes);
296
297 for(unsigned i=0;i<num_mutexes;++i)
298 {
299 BOOST_CHECK(mutexes[i].is_locked);
300 }
301 }
302
303 class dummy_iterator:
304 public std::iterator<std::forward_iterator_tag,
305 dummy_mutex>
306 {
307 private:
308 dummy_mutex* p;
309 public:
310 explicit dummy_iterator(dummy_mutex* p_):
311 p(p_)
312 {}
313
314 bool operator==(dummy_iterator const& other) const
315 {
316 return p==other.p;
317 }
318
319 bool operator!=(dummy_iterator const& other) const
320 {
321 return p!=other.p;
322 }
323
324 bool operator<(dummy_iterator const& other) const
325 {
326 return p<other.p;
327 }
328
329 dummy_mutex& operator*() const
330 {
331 return *p;
332 }
333
334 dummy_mutex* operator->() const
335 {
336 return p;
337 }
338
339 dummy_iterator operator++(int)
340 {
341 dummy_iterator temp(*this);
342 ++p;
343 return temp;
344 }
345
346 dummy_iterator& operator++()
347 {
348 ++p;
349 return *this;
350 }
351
352 };
353
354
355 BOOST_AUTO_TEST_CASE(test_lock_five_in_range_custom_iterator)
356 {
357 unsigned const num_mutexes=5;
358 dummy_mutex mutexes[num_mutexes];
359
360 boost::lock(dummy_iterator(mutexes),dummy_iterator(mutexes+num_mutexes));
361
362 for(unsigned i=0;i<num_mutexes;++i)
363 {
364 BOOST_CHECK(mutexes[i].is_locked);
365 }
366 }
367
368 class dummy_mutex2:
369 public dummy_mutex
370 {};
371
372
373 BOOST_AUTO_TEST_CASE(test_lock_ten_in_range_inherited_mutex)
374 {
375 unsigned const num_mutexes=10;
376 dummy_mutex2 mutexes[num_mutexes];
377
378 boost::lock(mutexes,mutexes+num_mutexes);
379
380 for(unsigned i=0;i<num_mutexes;++i)
381 {
382 BOOST_CHECK(mutexes[i].is_locked);
383 }
384 }
385
386 BOOST_AUTO_TEST_CASE(test_try_lock_two_uncontended)
387 {
388 dummy_mutex m1,m2;
389
390 int const res=boost::try_lock(m1,m2);
391
392 BOOST_CHECK(res==-1);
393 BOOST_CHECK(m1.is_locked);
394 BOOST_CHECK(m2.is_locked);
395 }
396 BOOST_AUTO_TEST_CASE(test_try_lock_two_first_locked)
397 {
398 dummy_mutex m1,m2;
399 m1.lock();
400
401 boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
402 l2(m2,boost::defer_lock);
403
404 int const res=boost::try_lock(l1,l2);
405
406 BOOST_CHECK(res==0);
407 BOOST_CHECK(m1.is_locked);
408 BOOST_CHECK(!m2.is_locked);
409 BOOST_CHECK(!l1.owns_lock());
410 BOOST_CHECK(!l2.owns_lock());
411 }
412 BOOST_AUTO_TEST_CASE(test_try_lock_two_second_locked)
413 {
414 dummy_mutex m1,m2;
415 m2.lock();
416
417 boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
418 l2(m2,boost::defer_lock);
419
420 int const res=boost::try_lock(l1,l2);
421
422 BOOST_CHECK(res==1);
423 BOOST_CHECK(!m1.is_locked);
424 BOOST_CHECK(m2.is_locked);
425 BOOST_CHECK(!l1.owns_lock());
426 BOOST_CHECK(!l2.owns_lock());
427 }
428
429 BOOST_AUTO_TEST_CASE(test_try_lock_three)
430 {
431 int const num_mutexes=3;
432
433 for(int i=-1;i<num_mutexes;++i)
434 {
435 dummy_mutex mutexes[num_mutexes];
436
437 if(i>=0)
438 {
439 mutexes[i].lock();
440 }
441 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
442 l2(mutexes[1],boost::defer_lock),
443 l3(mutexes[2],boost::defer_lock);
444
445 int const res=boost::try_lock(l1,l2,l3);
446
447 BOOST_CHECK(res==i);
448 for(int j=0;j<num_mutexes;++j)
449 {
450 if((i==j) || (i==-1))
451 {
452 BOOST_CHECK(mutexes[j].is_locked);
453 }
454 else
455 {
456 BOOST_CHECK(!mutexes[j].is_locked);
457 }
458 }
459 if(i==-1)
460 {
461 BOOST_CHECK(l1.owns_lock());
462 BOOST_CHECK(l2.owns_lock());
463 BOOST_CHECK(l3.owns_lock());
464 }
465 else
466 {
467 BOOST_CHECK(!l1.owns_lock());
468 BOOST_CHECK(!l2.owns_lock());
469 BOOST_CHECK(!l3.owns_lock());
470 }
471 }
472 }
473
474 BOOST_AUTO_TEST_CASE(test_try_lock_four)
475 {
476 int const num_mutexes=4;
477
478 for(int i=-1;i<num_mutexes;++i)
479 {
480 dummy_mutex mutexes[num_mutexes];
481
482 if(i>=0)
483 {
484 mutexes[i].lock();
485 }
486 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
487 l2(mutexes[1],boost::defer_lock),
488 l3(mutexes[2],boost::defer_lock),
489 l4(mutexes[3],boost::defer_lock);
490
491 int const res=boost::try_lock(l1,l2,l3,l4);
492
493 BOOST_CHECK(res==i);
494 for(int j=0;j<num_mutexes;++j)
495 {
496 if((i==j) || (i==-1))
497 {
498 BOOST_CHECK(mutexes[j].is_locked);
499 }
500 else
501 {
502 BOOST_CHECK(!mutexes[j].is_locked);
503 }
504 }
505 if(i==-1)
506 {
507 BOOST_CHECK(l1.owns_lock());
508 BOOST_CHECK(l2.owns_lock());
509 BOOST_CHECK(l3.owns_lock());
510 BOOST_CHECK(l4.owns_lock());
511 }
512 else
513 {
514 BOOST_CHECK(!l1.owns_lock());
515 BOOST_CHECK(!l2.owns_lock());
516 BOOST_CHECK(!l3.owns_lock());
517 BOOST_CHECK(!l4.owns_lock());
518 }
519 }
520 }
521
522 BOOST_AUTO_TEST_CASE(test_try_lock_five)
523 {
524 int const num_mutexes=5;
525
526 for(int i=-1;i<num_mutexes;++i)
527 {
528 dummy_mutex mutexes[num_mutexes];
529
530 if(i>=0)
531 {
532 mutexes[i].lock();
533 }
534 boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
535 l2(mutexes[1],boost::defer_lock),
536 l3(mutexes[2],boost::defer_lock),
537 l4(mutexes[3],boost::defer_lock),
538 l5(mutexes[4],boost::defer_lock);
539
540 int const res=boost::try_lock(l1,l2,l3,l4,l5);
541
542 BOOST_CHECK(res==i);
543 for(int j=0;j<num_mutexes;++j)
544 {
545 if((i==j) || (i==-1))
546 {
547 BOOST_CHECK(mutexes[j].is_locked);
548 }
549 else
550 {
551 BOOST_CHECK(!mutexes[j].is_locked);
552 }
553 }
554 if(i==-1)
555 {
556 BOOST_CHECK(l1.owns_lock());
557 BOOST_CHECK(l2.owns_lock());
558 BOOST_CHECK(l3.owns_lock());
559 BOOST_CHECK(l4.owns_lock());
560 BOOST_CHECK(l5.owns_lock());
561 }
562 else
563 {
564 BOOST_CHECK(!l1.owns_lock());
565 BOOST_CHECK(!l2.owns_lock());
566 BOOST_CHECK(!l3.owns_lock());
567 BOOST_CHECK(!l4.owns_lock());
568 BOOST_CHECK(!l5.owns_lock());
569 }
570 }
571 }
572