1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 &smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
19 #include <boost/thread/shared_mutex.hpp>
21 #include "common/ceph_time.h"
22 #include "common/shunique_lock.h"
24 #include "gtest/gtest.h"
26 template<typename SharedMutex>
27 static bool test_try_lock(SharedMutex* sm) {
34 template<typename SharedMutex>
35 static bool test_try_lock_shared(SharedMutex* sm) {
36 if (!sm->try_lock_shared())
42 template<typename SharedMutex, typename AcquireType>
43 static void check_conflicts(SharedMutex sm, AcquireType) {
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());
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());
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());
70 template<typename SharedMutex, typename AcquireType>
71 static void check_owns_lock(const SharedMutex& sm,
72 const ceph::shunique_lock<SharedMutex>& sul,
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());
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());
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());
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());
110 TEST(ShuniqueLock, DefaultConstructor) {
111 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
115 ASSERT_EQ(l.mutex(), nullptr);
116 ASSERT_FALSE(l.owns_lock());
119 ASSERT_THROW(l.lock(), std::system_error);
120 ASSERT_THROW(l.try_lock(), std::system_error);
122 ASSERT_THROW(l.lock_shared(), std::system_error);
123 ASSERT_THROW(l.try_lock_shared(), std::system_error);
125 ASSERT_THROW(l.unlock(), std::system_error);
127 ASSERT_EQ(l.mutex(), nullptr);
128 ASSERT_FALSE(l.owns_lock());
131 ASSERT_EQ(l.release(), nullptr);
133 ASSERT_EQ(l.mutex(), nullptr);
134 ASSERT_FALSE(l.owns_lock());
135 ASSERT_FALSE(l.owns_lock_shared());
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;
144 shunique_lock l(sm, at);
146 check_owns_lock(sm, l, at);
147 ensure_conflicts(sm, at);
151 check_abjures_lock(sm, l);
156 check_owns_lock(sm, l, at);
157 ensure_conflicts(sm, at);
160 TEST(ShuniqueLock, LockUnlock) {
161 lock_unlock(ceph::acquire_unique);
162 lock_unlock(ceph::acquire_shared);
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;
171 shunique_lock l(sm, at);
173 check_owns_lock(sm, l, at);
174 ensure_conflicts(sm, at);
180 TEST(ShuniqueLock, LockDestruct) {
181 lock_destruct(ceph::acquire_unique);
182 lock_destruct(ceph::acquire_shared);
185 template<typename AcquireType>
186 void move_construct(AcquireType at) {
187 boost::shared_mutex sm;
189 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
192 shunique_lock l(sm, at);
194 check_owns_lock(sm, l, at);
195 ensure_conflicts(sm, at);
197 shunique_lock o(std::move(l));
199 check_abjures_lock(l);
201 check_owns_lock(sm, o, at);
202 ensure_conflicts(sm, at);
206 shunique_lock c(std::move(o));
209 ASSERT_EQ(o.mutex(), nullptr);
212 check_abjures_lock(sm, c);
218 TEST(ShuniqueLock, MoveConstruct) {
219 move_construct(ceph::acquire_unique);
220 move_construct(ceph::acquire_shared);
222 boost::shared_mutex sm;
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);
231 std::unique_lock<boost::shared_mutex> ul(sm, std::defer_lock);
233 ceph::shunique_lock<boost::shared_mutex> l(std::move(ul));
234 check_abjures_lock(sm, l);
238 std::unique_lock<boost::shared_mutex> ul;
239 ceph::shunique_lock<boost::shared_mutex> l(std::move(ul));
240 check_abjures_lock(l);
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);
250 boost::shared_lock<boost::shared_mutex> sl;
251 ceph::shunique_lock<boost::shared_mutex> l(std::move(sl));
252 check_abjures_lock(l);
256 template<typename AcquireType>
257 void move_assign(AcquireType at) {
258 boost::shared_mutex sm;
260 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
263 shunique_lock l(sm, at);
265 check_owns_lock(sm, l, at);
266 ensure_conflicts(sm, at);
272 check_abjures_lock(l);
274 check_owns_lock(sm, o, at);
275 ensure_conflicts(sm, at);
279 shunique_lock c(std::move(o));
281 check_abjures_lock(o);
282 check_abjures_lock(sm, c);
290 check_abjures_lock(k);
291 check_abjures_lock(c);
297 TEST(ShuniqueLock, MoveAssign) {
298 move_assign(ceph::acquire_unique);
299 move_assign(ceph::acquire_shared);
301 boost::shared_mutex sm;
303 std::unique_lock<boost::shared_mutex> ul(sm);
304 ensure_conflicts(sm, ceph::acquire_unique);
305 ceph::shunique_lock<boost::shared_mutex> l;
307 check_owns_lock(sm, l, ceph::acquire_unique);
308 ensure_conflicts(sm, ceph::acquire_unique);
311 std::unique_lock<boost::shared_mutex> ul(sm, std::defer_lock);
313 ceph::shunique_lock<boost::shared_mutex> l;
315 check_abjures_lock(sm, l);
319 std::unique_lock<boost::shared_mutex> ul;
320 ceph::shunique_lock<boost::shared_mutex> l;
322 check_abjures_lock(l);
325 boost::shared_lock<boost::shared_mutex> sl(sm);
326 ensure_conflicts(sm, ceph::acquire_shared);
327 ceph::shunique_lock<boost::shared_mutex> l;
329 check_owns_lock(sm, l, ceph::acquire_shared);
330 ensure_conflicts(sm, ceph::acquire_shared);
333 boost::shared_lock<boost::shared_mutex> sl;
334 ceph::shunique_lock<boost::shared_mutex> l;
336 check_abjures_lock(l);
341 template<typename AcquireType>
342 void construct_deferred(AcquireType at) {
343 boost::shared_mutex sm;
345 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
348 shunique_lock l(sm, std::defer_lock);
349 check_abjures_lock(sm, l);
352 ASSERT_THROW(l.unlock(), std::system_error);
354 check_abjures_lock(sm, l);
358 check_owns_lock(sm, l, at);
359 ensure_conflicts(sm, at);
363 shunique_lock l(sm, std::defer_lock);
364 check_abjures_lock(sm, l);
367 ASSERT_THROW(l.unlock(), std::system_error);
369 check_abjures_lock(sm, l);
375 TEST(ShuniqueLock, ConstructDeferred) {
376 construct_deferred(ceph::acquire_unique);
377 construct_deferred(ceph::acquire_shared);
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;
386 shunique_lock l(sm, at, std::try_to_lock);
387 check_owns_lock(sm, l, at);
388 ensure_conflicts(sm, at);
392 std::unique_lock<boost::shared_mutex> l(sm);
393 ensure_conflicts(sm, ceph::acquire_unique);
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);
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);
411 TEST(ShuniqueLock, ConstructTry) {
412 construct_try(ceph::acquire_unique);
413 construct_try(ceph::acquire_shared);
416 template<typename AcquireType>
417 void construct_adopt(AcquireType at) {
418 boost::shared_mutex sm;
420 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
423 shunique_lock d(sm, at);
427 ensure_conflicts(sm, at);
430 shunique_lock l(sm, at, std::adopt_lock);
431 check_owns_lock(sm, l, at);
432 ensure_conflicts(sm, at);
438 TEST(ShuniqueLock, ConstructAdopt) {
439 construct_adopt(ceph::acquire_unique);
440 construct_adopt(ceph::acquire_shared);
443 template<typename AcquireType>
444 void try_lock(AcquireType at) {
445 boost::shared_mutex sm;
447 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
450 shunique_lock l(sm, std::defer_lock);
453 check_owns_lock(sm, l, at);
454 ensure_conflicts(sm, at);
458 std::unique_lock<boost::shared_mutex> l(sm);
460 std::async(std::launch::async, [&sm, at]() {
461 shunique_lock l(sm, std::defer_lock);
464 check_abjures_lock(sm, l);
465 ensure_conflicts(sm, ceph::acquire_unique);
470 std::async(std::launch::async, [&sm, at]() {
471 shunique_lock l(sm, std::defer_lock);
474 check_owns_lock(sm, l, at);
475 ensure_conflicts(sm, at);
480 TEST(ShuniqueLock, TryLock) {
481 try_lock(ceph::acquire_unique);
482 try_lock(ceph::acquire_shared);
485 TEST(ShuniqueLock, Release) {
486 boost::shared_mutex sm;
487 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
490 shunique_lock l(sm, ceph::acquire_unique);
491 check_owns_lock(sm, l, ceph::acquire_unique);
492 ensure_conflicts(sm, ceph::acquire_unique);
495 check_abjures_lock(l);
496 ensure_conflicts(sm, ceph::acquire_unique);
498 ensure_conflicts(sm, ceph::acquire_unique);
503 shunique_lock l(sm, ceph::acquire_shared);
504 check_owns_lock(sm, l, ceph::acquire_shared);
505 ensure_conflicts(sm, ceph::acquire_shared);
508 check_abjures_lock(l);
509 ensure_conflicts(sm, ceph::acquire_shared);
511 ensure_conflicts(sm, ceph::acquire_shared);
517 shunique_lock l(sm, std::defer_lock);
518 check_abjures_lock(sm, l);
519 ensure_conflicts(sm, ceph::acquire_unique);
522 check_abjures_lock(l);
523 ensure_conflicts(sm, ceph::acquire_unique);
525 ensure_conflicts(sm, ceph::acquire_unique);
531 std::unique_lock<boost::shared_mutex> ul;
532 shunique_lock l(sm, std::defer_lock);
533 check_abjures_lock(sm, l);
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());
545 std::unique_lock<boost::shared_mutex> ul;
547 check_abjures_lock(l);
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());
556 TEST(ShuniqueLock, NoRecursion) {
557 boost::shared_mutex sm;
559 typedef ceph::shunique_lock<boost::shared_mutex> shunique_lock;
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);
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);