Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / common / test_shunique_lock.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 &smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2011 New Dream Network
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License version 2, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include <future>
16 #include <mutex>
17 #include <thread>
18
19 #include <boost/thread/shared_mutex.hpp>
20
21 #include "common/ceph_time.h"
22 #include "common/shunique_lock.h"
23
24 #include "gtest/gtest.h"
25
26 template<typename SharedMutex>
27 static bool test_try_lock(SharedMutex* sm) {
28   if (!sm->try_lock())
29     return false;
30   sm->unlock();
31   return true;
32 }
33
34 template<typename SharedMutex>
35 static bool test_try_lock_shared(SharedMutex* sm) {
36   if (!sm->try_lock_shared())
37     return false;
38   sm->unlock_shared();
39   return true;
40 }
41
42 template<typename SharedMutex, typename AcquireType>
43 static void check_conflicts(SharedMutex sm, AcquireType) {
44 }
45
46 template<typename SharedMutex>
47 static void ensure_conflicts(SharedMutex& sm, ceph::acquire_unique_t) {
48   auto ttl = &test_try_lock<boost::shared_mutex>;
49   auto ttls = &test_try_lock_shared<boost::shared_mutex>;
50   ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get());
51   ASSERT_FALSE(std::async(std::launch::async, ttls, &sm).get());
52 }
53
54 template<typename SharedMutex>
55 static void ensure_conflicts(SharedMutex& sm, ceph::acquire_shared_t) {
56   auto ttl = &test_try_lock<boost::shared_mutex>;
57   auto ttls = &test_try_lock_shared<boost::shared_mutex>;
58   ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get());
59   ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get());
60 }
61
62 template<typename SharedMutex>
63 static void ensure_free(SharedMutex& sm) {
64   auto ttl = &test_try_lock<boost::shared_mutex>;
65   auto ttls = &test_try_lock_shared<boost::shared_mutex>;
66   ASSERT_TRUE(std::async(std::launch::async, ttl, &sm).get());
67   ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get());
68 }
69
70 template<typename SharedMutex, typename AcquireType>
71 static void check_owns_lock(const SharedMutex& sm,
72                             const ceph::shunique_lock<SharedMutex>& sul,
73                             AcquireType) {
74 }
75
76 template<typename SharedMutex>
77 static void check_owns_lock(const SharedMutex& sm,
78                             const ceph::shunique_lock<SharedMutex>& sul,
79                             ceph::acquire_unique_t) {
80   ASSERT_TRUE(sul.mutex() == &sm);
81   ASSERT_TRUE(sul.owns_lock());
82   ASSERT_TRUE(!!sul);
83 }
84
85 template<typename SharedMutex>
86 static void check_owns_lock(const SharedMutex& sm,
87                             const ceph::shunique_lock<SharedMutex>& sul,
88                             ceph::acquire_shared_t) {
89   ASSERT_TRUE(sul.owns_lock_shared());
90   ASSERT_TRUE(!!sul);
91 }
92
93 template<typename SharedMutex>
94 static void check_abjures_lock(const SharedMutex& sm,
95                                const ceph::shunique_lock<SharedMutex>& sul) {
96   ASSERT_EQ(sul.mutex(), &sm);
97   ASSERT_FALSE(sul.owns_lock());
98   ASSERT_FALSE(sul.owns_lock_shared());
99   ASSERT_FALSE(!!sul);
100 }
101
102 template<typename SharedMutex>
103 static void check_abjures_lock(const ceph::shunique_lock<SharedMutex>& sul) {
104   ASSERT_EQ(sul.mutex(), nullptr);
105   ASSERT_FALSE(sul.owns_lock());
106   ASSERT_FALSE(sul.owns_lock_shared());
107   ASSERT_FALSE(!!sul);
108 }
109
110 TEST(ShuniqueLock, DefaultConstructor) {
111   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
112
113   shunique_lock l;
114
115   ASSERT_EQ(l.mutex(), nullptr);
116   ASSERT_FALSE(l.owns_lock());
117   ASSERT_FALSE(!!l);
118
119   ASSERT_THROW(l.lock(), std::system_error);
120   ASSERT_THROW(l.try_lock(), std::system_error);
121
122   ASSERT_THROW(l.lock_shared(), std::system_error);
123   ASSERT_THROW(l.try_lock_shared(), std::system_error);
124
125   ASSERT_THROW(l.unlock(), std::system_error);
126
127   ASSERT_EQ(l.mutex(), nullptr);
128   ASSERT_FALSE(l.owns_lock());
129   ASSERT_FALSE(!!l);
130
131   ASSERT_EQ(l.release(), nullptr);
132
133   ASSERT_EQ(l.mutex(), nullptr);
134   ASSERT_FALSE(l.owns_lock());
135   ASSERT_FALSE(l.owns_lock_shared());
136   ASSERT_FALSE(!!l);
137 }
138
139 template<typename AcquireType>
140 void lock_unlock(AcquireType at) {
141   boost::shared_mutex sm;
142   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
143
144   shunique_lock l(sm, at);
145
146   check_owns_lock(sm, l, at);
147   ensure_conflicts(sm, at);
148
149   l.unlock();
150
151   check_abjures_lock(sm, l);
152   ensure_free(sm);
153
154   l.lock(at);
155
156   check_owns_lock(sm, l, at);
157   ensure_conflicts(sm, at);
158 }
159
160 TEST(ShuniqueLock, LockUnlock) {
161   lock_unlock(ceph::acquire_unique);
162   lock_unlock(ceph::acquire_shared);
163 }
164
165 template<typename AcquireType>
166 void lock_destruct(AcquireType at) {
167   boost::shared_mutex sm;
168   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
169
170   {
171     shunique_lock l(sm, at);
172
173     check_owns_lock(sm, l, at);
174     ensure_conflicts(sm, at);
175   }
176
177   ensure_free(sm);
178 }
179
180 TEST(ShuniqueLock, LockDestruct) {
181   lock_destruct(ceph::acquire_unique);
182   lock_destruct(ceph::acquire_shared);
183 }
184
185 template<typename AcquireType>
186 void move_construct(AcquireType at) {
187   boost::shared_mutex sm;
188
189   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
190
191   {
192     shunique_lock l(sm, at);
193
194     check_owns_lock(sm, l, at);
195     ensure_conflicts(sm, at);
196
197     shunique_lock o(std::move(l));
198
199     check_abjures_lock(l);
200
201     check_owns_lock(sm, o, at);
202     ensure_conflicts(sm, at);
203
204     o.unlock();
205
206     shunique_lock c(std::move(o));
207
208
209     ASSERT_EQ(o.mutex(), nullptr);
210     ASSERT_FALSE(!!o);
211
212     check_abjures_lock(sm, c);
213
214     ensure_free(sm);
215   }
216 }
217
218 TEST(ShuniqueLock, MoveConstruct) {
219   move_construct(ceph::acquire_unique);
220   move_construct(ceph::acquire_shared);
221
222   boost::shared_mutex sm;
223   {
224     std::unique_lock<boost::shared_mutex> ul(sm);
225     ensure_conflicts(sm, ceph::acquire_unique);
226     ceph::shunique_lock<boost::shared_mutex> l(std::move(ul));
227     check_owns_lock(sm, l, ceph::acquire_unique);
228     ensure_conflicts(sm, ceph::acquire_unique);
229   }
230   {
231     std::unique_lock<boost::shared_mutex> ul(sm, std::defer_lock);
232     ensure_free(sm);
233     ceph::shunique_lock<boost::shared_mutex> l(std::move(ul));
234     check_abjures_lock(sm, l);
235     ensure_free(sm);
236   }
237   {
238     std::unique_lock<boost::shared_mutex> ul;
239     ceph::shunique_lock<boost::shared_mutex> l(std::move(ul));
240     check_abjures_lock(l);
241   }
242   {
243     boost::shared_lock<boost::shared_mutex> sl(sm);
244     ensure_conflicts(sm, ceph::acquire_shared);
245     ceph::shunique_lock<boost::shared_mutex> l(std::move(sl));
246     check_owns_lock(sm, l, ceph::acquire_shared);
247     ensure_conflicts(sm, ceph::acquire_shared);
248   }
249   {
250     boost::shared_lock<boost::shared_mutex> sl;
251     ceph::shunique_lock<boost::shared_mutex> l(std::move(sl));
252     check_abjures_lock(l);
253   }
254 }
255
256 template<typename AcquireType>
257 void move_assign(AcquireType at) {
258   boost::shared_mutex sm;
259
260   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
261
262   {
263     shunique_lock l(sm, at);
264
265     check_owns_lock(sm, l, at);
266     ensure_conflicts(sm, at);
267
268     shunique_lock o;
269
270     o = std::move(l);
271
272     check_abjures_lock(l);
273
274     check_owns_lock(sm, o, at);
275     ensure_conflicts(sm, at);
276
277     o.unlock();
278
279     shunique_lock c(std::move(o));
280
281     check_abjures_lock(o);
282     check_abjures_lock(sm, c);
283
284     ensure_free(sm);
285
286     shunique_lock k;
287
288     c = std::move(k);
289
290     check_abjures_lock(k);
291     check_abjures_lock(c);
292
293     ensure_free(sm);
294   }
295 }
296
297 TEST(ShuniqueLock, MoveAssign) {
298   move_assign(ceph::acquire_unique);
299   move_assign(ceph::acquire_shared);
300
301   boost::shared_mutex sm;
302   {
303     std::unique_lock<boost::shared_mutex> ul(sm);
304     ensure_conflicts(sm, ceph::acquire_unique);
305     ceph::shunique_lock<boost::shared_mutex> l;
306     l = std::move(ul);
307     check_owns_lock(sm, l, ceph::acquire_unique);
308     ensure_conflicts(sm, ceph::acquire_unique);
309   }
310   {
311     std::unique_lock<boost::shared_mutex> ul(sm, std::defer_lock);
312     ensure_free(sm);
313     ceph::shunique_lock<boost::shared_mutex> l;
314     l = std::move(ul);
315     check_abjures_lock(sm, l);
316     ensure_free(sm);
317   }
318   {
319     std::unique_lock<boost::shared_mutex> ul;
320     ceph::shunique_lock<boost::shared_mutex> l;
321     l = std::move(ul);
322     check_abjures_lock(l);
323   }
324   {
325     boost::shared_lock<boost::shared_mutex> sl(sm);
326     ensure_conflicts(sm, ceph::acquire_shared);
327     ceph::shunique_lock<boost::shared_mutex> l;
328     l = std::move(sl);
329     check_owns_lock(sm, l, ceph::acquire_shared);
330     ensure_conflicts(sm, ceph::acquire_shared);
331   }
332   {
333     boost::shared_lock<boost::shared_mutex> sl;
334     ceph::shunique_lock<boost::shared_mutex> l;
335     l = std::move(sl);
336     check_abjures_lock(l);
337   }
338
339 }
340
341 template<typename AcquireType>
342 void construct_deferred(AcquireType at) {
343   boost::shared_mutex sm;
344
345   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
346
347   {
348     shunique_lock l(sm, std::defer_lock);
349     check_abjures_lock(sm, l);
350     ensure_free(sm);
351
352     ASSERT_THROW(l.unlock(), std::system_error);
353
354     check_abjures_lock(sm, l);
355     ensure_free(sm);
356
357     l.lock(at);
358     check_owns_lock(sm, l, at);
359     ensure_conflicts(sm, at);
360   }
361
362   {
363     shunique_lock l(sm, std::defer_lock);
364     check_abjures_lock(sm, l);
365     ensure_free(sm);
366
367     ASSERT_THROW(l.unlock(), std::system_error);
368
369     check_abjures_lock(sm, l);
370     ensure_free(sm);
371   }
372   ensure_free(sm);
373 }
374
375 TEST(ShuniqueLock, ConstructDeferred) {
376   construct_deferred(ceph::acquire_unique);
377   construct_deferred(ceph::acquire_shared);
378 }
379
380 template<typename AcquireType>
381 void construct_try(AcquireType at) {
382   boost::shared_mutex sm;
383   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
384
385   {
386     shunique_lock l(sm, at, std::try_to_lock);
387     check_owns_lock(sm, l, at);
388     ensure_conflicts(sm, at);
389   }
390
391   {
392     std::unique_lock<boost::shared_mutex> l(sm);
393     ensure_conflicts(sm, ceph::acquire_unique);
394
395     std::async(std::launch::async, [&sm, at]() {
396         shunique_lock l(sm, at, std::try_to_lock);
397         check_abjures_lock(sm, l);
398         ensure_conflicts(sm, ceph::acquire_unique);
399       }).get();
400
401     l.unlock();
402
403     std::async(std::launch::async, [&sm, at]() {
404         shunique_lock l(sm, at, std::try_to_lock);
405         check_owns_lock(sm, l, at);
406         ensure_conflicts(sm, at);
407       }).get();
408   }
409 }
410
411 TEST(ShuniqueLock, ConstructTry) {
412   construct_try(ceph::acquire_unique);
413   construct_try(ceph::acquire_shared);
414 }
415
416 template<typename AcquireType>
417 void construct_adopt(AcquireType at) {
418   boost::shared_mutex sm;
419
420   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
421
422   {
423     shunique_lock d(sm, at);
424     d.release();
425   }
426
427   ensure_conflicts(sm, at);
428
429   {
430     shunique_lock l(sm, at, std::adopt_lock);
431     check_owns_lock(sm, l, at);
432     ensure_conflicts(sm, at);
433   }
434
435   ensure_free(sm);
436 }
437
438 TEST(ShuniqueLock, ConstructAdopt) {
439   construct_adopt(ceph::acquire_unique);
440   construct_adopt(ceph::acquire_shared);
441 }
442
443 template<typename AcquireType>
444 void try_lock(AcquireType at) {
445   boost::shared_mutex sm;
446
447   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
448
449   {
450     shunique_lock l(sm, std::defer_lock);
451     l.try_lock(at);
452
453     check_owns_lock(sm, l, at);
454     ensure_conflicts(sm, at);
455   }
456
457   {
458     std::unique_lock<boost::shared_mutex> l(sm);
459
460     std::async(std::launch::async, [&sm, at]() {
461         shunique_lock l(sm, std::defer_lock);
462         l.try_lock(at);
463
464         check_abjures_lock(sm, l);
465         ensure_conflicts(sm, ceph::acquire_unique);
466       }).get();
467
468
469     l.unlock();
470     std::async(std::launch::async, [&sm, at]() {
471         shunique_lock l(sm, std::defer_lock);
472         l.try_lock(at);
473
474         check_owns_lock(sm, l, at);
475         ensure_conflicts(sm, at);
476       }).get();
477   }
478 }
479
480 TEST(ShuniqueLock, TryLock) {
481   try_lock(ceph::acquire_unique);
482   try_lock(ceph::acquire_shared);
483 }
484
485 TEST(ShuniqueLock, Release) {
486   boost::shared_mutex sm;
487   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
488
489   {
490     shunique_lock l(sm, ceph::acquire_unique);
491     check_owns_lock(sm, l, ceph::acquire_unique);
492     ensure_conflicts(sm, ceph::acquire_unique);
493
494     l.release();
495     check_abjures_lock(l);
496     ensure_conflicts(sm, ceph::acquire_unique);
497   }
498   ensure_conflicts(sm, ceph::acquire_unique);
499   sm.unlock();
500   ensure_free(sm);
501
502   {
503     shunique_lock l(sm, ceph::acquire_shared);
504     check_owns_lock(sm, l, ceph::acquire_shared);
505     ensure_conflicts(sm, ceph::acquire_shared);
506
507     l.release();
508     check_abjures_lock(l);
509     ensure_conflicts(sm, ceph::acquire_shared);
510   }
511   ensure_conflicts(sm, ceph::acquire_shared);
512   sm.unlock_shared();
513   ensure_free(sm);
514
515   sm.lock();
516   {
517     shunique_lock l(sm, std::defer_lock);
518     check_abjures_lock(sm, l);
519     ensure_conflicts(sm, ceph::acquire_unique);
520
521     l.release();
522     check_abjures_lock(l);
523     ensure_conflicts(sm, ceph::acquire_unique);
524   }
525   ensure_conflicts(sm, ceph::acquire_unique);
526   sm.unlock();
527
528   ensure_free(sm);
529
530   {
531     std::unique_lock<boost::shared_mutex> ul;
532     shunique_lock l(sm, std::defer_lock);
533     check_abjures_lock(sm, l);
534     ensure_free(sm);
535
536     ASSERT_NO_THROW(ul = l.release_to_unique());
537     check_abjures_lock(l);
538     ASSERT_EQ(ul.mutex(), &sm);
539     ASSERT_FALSE(ul.owns_lock());
540     ensure_free(sm);
541   }
542   ensure_free(sm);
543
544   {
545     std::unique_lock<boost::shared_mutex> ul;
546     shunique_lock l;
547     check_abjures_lock(l);
548
549     ASSERT_NO_THROW(ul = l.release_to_unique());
550     check_abjures_lock(l);
551     ASSERT_EQ(ul.mutex(), nullptr);
552     ASSERT_FALSE(ul.owns_lock());
553   }
554 }
555
556 TEST(ShuniqueLock, NoRecursion) {
557   boost::shared_mutex sm;
558
559   typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
560
561   {
562     shunique_lock l(sm, ceph::acquire_unique);
563     ASSERT_THROW(l.lock(), std::system_error);
564     ASSERT_THROW(l.try_lock(), std::system_error);
565     ASSERT_THROW(l.lock_shared(), std::system_error);
566     ASSERT_THROW(l.try_lock_shared(), std::system_error);
567   }
568
569   {
570     shunique_lock l(sm, ceph::acquire_shared);
571     ASSERT_THROW(l.lock(), std::system_error);
572     ASSERT_THROW(l.try_lock(), std::system_error);
573     ASSERT_THROW(l.lock_shared(), std::system_error);
574     ASSERT_THROW(l.try_lock_shared(), std::system_error);
575   }
576 }