summaryrefslogtreecommitdiffstats
path: root/src/test/common/test_shunique_lock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/common/test_shunique_lock.cc')
-rw-r--r--src/test/common/test_shunique_lock.cc575
1 files changed, 575 insertions, 0 deletions
diff --git a/src/test/common/test_shunique_lock.cc b/src/test/common/test_shunique_lock.cc
new file mode 100644
index 000000000..b7696fe6e
--- /dev/null
+++ b/src/test/common/test_shunique_lock.cc
@@ -0,0 +1,575 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 &smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <future>
+#include <mutex>
+#include <shared_mutex>
+#include <thread>
+
+#include "common/ceph_time.h"
+#include "common/shunique_lock.h"
+
+#include "gtest/gtest.h"
+
+template<typename SharedMutex>
+static bool test_try_lock(SharedMutex* sm) {
+ if (!sm->try_lock())
+ return false;
+ sm->unlock();
+ return true;
+}
+
+template<typename SharedMutex>
+static bool test_try_lock_shared(SharedMutex* sm) {
+ if (!sm->try_lock_shared())
+ return false;
+ sm->unlock_shared();
+ return true;
+}
+
+template<typename SharedMutex, typename AcquireType>
+static void check_conflicts(SharedMutex sm, AcquireType) {
+}
+
+template<typename SharedMutex>
+static void ensure_conflicts(SharedMutex& sm, ceph::acquire_unique_t) {
+ auto ttl = &test_try_lock<std::shared_timed_mutex>;
+ auto ttls = &test_try_lock_shared<std::shared_timed_mutex>;
+ ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get());
+ ASSERT_FALSE(std::async(std::launch::async, ttls, &sm).get());
+}
+
+template<typename SharedMutex>
+static void ensure_conflicts(SharedMutex& sm, ceph::acquire_shared_t) {
+ auto ttl = &test_try_lock<std::shared_timed_mutex>;
+ auto ttls = &test_try_lock_shared<std::shared_timed_mutex>;
+ ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get());
+ ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get());
+}
+
+template<typename SharedMutex>
+static void ensure_free(SharedMutex& sm) {
+ auto ttl = &test_try_lock<std::shared_timed_mutex>;
+ auto ttls = &test_try_lock_shared<std::shared_timed_mutex>;
+ ASSERT_TRUE(std::async(std::launch::async, ttl, &sm).get());
+ ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get());
+}
+
+template<typename SharedMutex, typename AcquireType>
+static void check_owns_lock(const SharedMutex& sm,
+ const ceph::shunique_lock<SharedMutex>& sul,
+ AcquireType) {
+}
+
+template<typename SharedMutex>
+static void check_owns_lock(const SharedMutex& sm,
+ const ceph::shunique_lock<SharedMutex>& sul,
+ ceph::acquire_unique_t) {
+ ASSERT_TRUE(sul.mutex() == &sm);
+ ASSERT_TRUE(sul.owns_lock());
+ ASSERT_TRUE(!!sul);
+}
+
+template<typename SharedMutex>
+static void check_owns_lock(const SharedMutex& sm,
+ const ceph::shunique_lock<SharedMutex>& sul,
+ ceph::acquire_shared_t) {
+ ASSERT_TRUE(sul.owns_lock_shared());
+ ASSERT_TRUE(!!sul);
+}
+
+template<typename SharedMutex>
+static void check_abjures_lock(const SharedMutex& sm,
+ const ceph::shunique_lock<SharedMutex>& sul) {
+ ASSERT_EQ(sul.mutex(), &sm);
+ ASSERT_FALSE(sul.owns_lock());
+ ASSERT_FALSE(sul.owns_lock_shared());
+ ASSERT_FALSE(!!sul);
+}
+
+template<typename SharedMutex>
+static void check_abjures_lock(const ceph::shunique_lock<SharedMutex>& sul) {
+ ASSERT_EQ(sul.mutex(), nullptr);
+ ASSERT_FALSE(sul.owns_lock());
+ ASSERT_FALSE(sul.owns_lock_shared());
+ ASSERT_FALSE(!!sul);
+}
+
+TEST(ShuniqueLock, DefaultConstructor) {
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ shunique_lock l;
+
+ ASSERT_EQ(l.mutex(), nullptr);
+ ASSERT_FALSE(l.owns_lock());
+ ASSERT_FALSE(!!l);
+
+ ASSERT_THROW(l.lock(), std::system_error);
+ ASSERT_THROW(l.try_lock(), std::system_error);
+
+ ASSERT_THROW(l.lock_shared(), std::system_error);
+ ASSERT_THROW(l.try_lock_shared(), std::system_error);
+
+ ASSERT_THROW(l.unlock(), std::system_error);
+
+ ASSERT_EQ(l.mutex(), nullptr);
+ ASSERT_FALSE(l.owns_lock());
+ ASSERT_FALSE(!!l);
+
+ ASSERT_EQ(l.release(), nullptr);
+
+ ASSERT_EQ(l.mutex(), nullptr);
+ ASSERT_FALSE(l.owns_lock());
+ ASSERT_FALSE(l.owns_lock_shared());
+ ASSERT_FALSE(!!l);
+}
+
+template<typename AcquireType>
+void lock_unlock(AcquireType at) {
+ std::shared_timed_mutex sm;
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ shunique_lock l(sm, at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+
+ l.unlock();
+
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+
+ l.lock(at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+}
+
+TEST(ShuniqueLock, LockUnlock) {
+ lock_unlock(ceph::acquire_unique);
+ lock_unlock(ceph::acquire_shared);
+}
+
+template<typename AcquireType>
+void lock_destruct(AcquireType at) {
+ std::shared_timed_mutex sm;
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }
+
+ ensure_free(sm);
+}
+
+TEST(ShuniqueLock, LockDestruct) {
+ lock_destruct(ceph::acquire_unique);
+ lock_destruct(ceph::acquire_shared);
+}
+
+template<typename AcquireType>
+void move_construct(AcquireType at) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+
+ shunique_lock o(std::move(l));
+
+ check_abjures_lock(l);
+
+ check_owns_lock(sm, o, at);
+ ensure_conflicts(sm, at);
+
+ o.unlock();
+
+ shunique_lock c(std::move(o));
+
+
+ ASSERT_EQ(o.mutex(), nullptr);
+ ASSERT_FALSE(!!o);
+
+ check_abjures_lock(sm, c);
+
+ ensure_free(sm);
+ }
+}
+
+TEST(ShuniqueLock, MoveConstruct) {
+ move_construct(ceph::acquire_unique);
+ move_construct(ceph::acquire_shared);
+
+ std::shared_timed_mutex sm;
+ {
+ std::unique_lock<std::shared_timed_mutex> ul(sm);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ ceph::shunique_lock<std::shared_timed_mutex> l(std::move(ul));
+ check_owns_lock(sm, l, ceph::acquire_unique);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }
+ {
+ std::unique_lock<std::shared_timed_mutex> ul(sm, std::defer_lock);
+ ensure_free(sm);
+ ceph::shunique_lock<std::shared_timed_mutex> l(std::move(ul));
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+ }
+ {
+ std::unique_lock<std::shared_timed_mutex> ul;
+ ceph::shunique_lock<std::shared_timed_mutex> l(std::move(ul));
+ check_abjures_lock(l);
+ }
+ {
+ std::shared_lock<std::shared_timed_mutex> sl(sm);
+ ensure_conflicts(sm, ceph::acquire_shared);
+ ceph::shunique_lock<std::shared_timed_mutex> l(std::move(sl));
+ check_owns_lock(sm, l, ceph::acquire_shared);
+ ensure_conflicts(sm, ceph::acquire_shared);
+ }
+ {
+ std::shared_lock<std::shared_timed_mutex> sl;
+ ceph::shunique_lock<std::shared_timed_mutex> l(std::move(sl));
+ check_abjures_lock(l);
+ }
+}
+
+template<typename AcquireType>
+void move_assign(AcquireType at) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+
+ shunique_lock o;
+
+ o = std::move(l);
+
+ check_abjures_lock(l);
+
+ check_owns_lock(sm, o, at);
+ ensure_conflicts(sm, at);
+
+ o.unlock();
+
+ shunique_lock c(std::move(o));
+
+ check_abjures_lock(o);
+ check_abjures_lock(sm, c);
+
+ ensure_free(sm);
+
+ shunique_lock k;
+
+ c = std::move(k);
+
+ check_abjures_lock(k);
+ check_abjures_lock(c);
+
+ ensure_free(sm);
+ }
+}
+
+TEST(ShuniqueLock, MoveAssign) {
+ move_assign(ceph::acquire_unique);
+ move_assign(ceph::acquire_shared);
+
+ std::shared_timed_mutex sm;
+ {
+ std::unique_lock<std::shared_timed_mutex> ul(sm);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ ceph::shunique_lock<std::shared_timed_mutex> l;
+ l = std::move(ul);
+ check_owns_lock(sm, l, ceph::acquire_unique);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }
+ {
+ std::unique_lock<std::shared_timed_mutex> ul(sm, std::defer_lock);
+ ensure_free(sm);
+ ceph::shunique_lock<std::shared_timed_mutex> l;
+ l = std::move(ul);
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+ }
+ {
+ std::unique_lock<std::shared_timed_mutex> ul;
+ ceph::shunique_lock<std::shared_timed_mutex> l;
+ l = std::move(ul);
+ check_abjures_lock(l);
+ }
+ {
+ std::shared_lock<std::shared_timed_mutex> sl(sm);
+ ensure_conflicts(sm, ceph::acquire_shared);
+ ceph::shunique_lock<std::shared_timed_mutex> l;
+ l = std::move(sl);
+ check_owns_lock(sm, l, ceph::acquire_shared);
+ ensure_conflicts(sm, ceph::acquire_shared);
+ }
+ {
+ std::shared_lock<std::shared_timed_mutex> sl;
+ ceph::shunique_lock<std::shared_timed_mutex> l;
+ l = std::move(sl);
+ check_abjures_lock(l);
+ }
+
+}
+
+template<typename AcquireType>
+void construct_deferred(AcquireType at) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, std::defer_lock);
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+
+ ASSERT_THROW(l.unlock(), std::system_error);
+
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+
+ l.lock(at);
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }
+
+ {
+ shunique_lock l(sm, std::defer_lock);
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+
+ ASSERT_THROW(l.unlock(), std::system_error);
+
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+ }
+ ensure_free(sm);
+}
+
+TEST(ShuniqueLock, ConstructDeferred) {
+ construct_deferred(ceph::acquire_unique);
+ construct_deferred(ceph::acquire_shared);
+}
+
+template<typename AcquireType>
+void construct_try(AcquireType at) {
+ std::shared_timed_mutex sm;
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, at, std::try_to_lock);
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }
+
+ {
+ std::unique_lock<std::shared_timed_mutex> l(sm);
+ ensure_conflicts(sm, ceph::acquire_unique);
+
+ std::async(std::launch::async, [&sm, at]() {
+ shunique_lock l(sm, at, std::try_to_lock);
+ check_abjures_lock(sm, l);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }).get();
+
+ l.unlock();
+
+ std::async(std::launch::async, [&sm, at]() {
+ shunique_lock l(sm, at, std::try_to_lock);
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }).get();
+ }
+}
+
+TEST(ShuniqueLock, ConstructTry) {
+ construct_try(ceph::acquire_unique);
+ construct_try(ceph::acquire_shared);
+}
+
+template<typename AcquireType>
+void construct_adopt(AcquireType at) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock d(sm, at);
+ d.release();
+ }
+
+ ensure_conflicts(sm, at);
+
+ {
+ shunique_lock l(sm, at, std::adopt_lock);
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }
+
+ ensure_free(sm);
+}
+
+TEST(ShuniqueLock, ConstructAdopt) {
+ construct_adopt(ceph::acquire_unique);
+ construct_adopt(ceph::acquire_shared);
+}
+
+template<typename AcquireType>
+void try_lock(AcquireType at) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, std::defer_lock);
+ l.try_lock(at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }
+
+ {
+ std::unique_lock<std::shared_timed_mutex> l(sm);
+
+ std::async(std::launch::async, [&sm, at]() {
+ shunique_lock l(sm, std::defer_lock);
+ l.try_lock(at);
+
+ check_abjures_lock(sm, l);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }).get();
+
+
+ l.unlock();
+ std::async(std::launch::async, [&sm, at]() {
+ shunique_lock l(sm, std::defer_lock);
+ l.try_lock(at);
+
+ check_owns_lock(sm, l, at);
+ ensure_conflicts(sm, at);
+ }).get();
+ }
+}
+
+TEST(ShuniqueLock, TryLock) {
+ try_lock(ceph::acquire_unique);
+ try_lock(ceph::acquire_shared);
+}
+
+TEST(ShuniqueLock, Release) {
+ std::shared_timed_mutex sm;
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, ceph::acquire_unique);
+ check_owns_lock(sm, l, ceph::acquire_unique);
+ ensure_conflicts(sm, ceph::acquire_unique);
+
+ l.release();
+ check_abjures_lock(l);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }
+ ensure_conflicts(sm, ceph::acquire_unique);
+ sm.unlock();
+ ensure_free(sm);
+
+ {
+ shunique_lock l(sm, ceph::acquire_shared);
+ check_owns_lock(sm, l, ceph::acquire_shared);
+ ensure_conflicts(sm, ceph::acquire_shared);
+
+ l.release();
+ check_abjures_lock(l);
+ ensure_conflicts(sm, ceph::acquire_shared);
+ }
+ ensure_conflicts(sm, ceph::acquire_shared);
+ sm.unlock_shared();
+ ensure_free(sm);
+
+ sm.lock();
+ {
+ shunique_lock l(sm, std::defer_lock);
+ check_abjures_lock(sm, l);
+ ensure_conflicts(sm, ceph::acquire_unique);
+
+ l.release();
+ check_abjures_lock(l);
+ ensure_conflicts(sm, ceph::acquire_unique);
+ }
+ ensure_conflicts(sm, ceph::acquire_unique);
+ sm.unlock();
+
+ ensure_free(sm);
+
+ {
+ std::unique_lock<std::shared_timed_mutex> ul;
+ shunique_lock l(sm, std::defer_lock);
+ check_abjures_lock(sm, l);
+ ensure_free(sm);
+
+ ASSERT_NO_THROW(ul = l.release_to_unique());
+ check_abjures_lock(l);
+ ASSERT_EQ(ul.mutex(), &sm);
+ ASSERT_FALSE(ul.owns_lock());
+ ensure_free(sm);
+ }
+ ensure_free(sm);
+
+ {
+ std::unique_lock<std::shared_timed_mutex> ul;
+ shunique_lock l;
+ check_abjures_lock(l);
+
+ ASSERT_NO_THROW(ul = l.release_to_unique());
+ check_abjures_lock(l);
+ ASSERT_EQ(ul.mutex(), nullptr);
+ ASSERT_FALSE(ul.owns_lock());
+ }
+}
+
+TEST(ShuniqueLock, NoRecursion) {
+ std::shared_timed_mutex sm;
+
+ typedef ceph::shunique_lock<std::shared_timed_mutex> shunique_lock;
+
+ {
+ shunique_lock l(sm, ceph::acquire_unique);
+ ASSERT_THROW(l.lock(), std::system_error);
+ ASSERT_THROW(l.try_lock(), std::system_error);
+ ASSERT_THROW(l.lock_shared(), std::system_error);
+ ASSERT_THROW(l.try_lock_shared(), std::system_error);
+ }
+
+ {
+ shunique_lock l(sm, ceph::acquire_shared);
+ ASSERT_THROW(l.lock(), std::system_error);
+ ASSERT_THROW(l.try_lock(), std::system_error);
+ ASSERT_THROW(l.lock_shared(), std::system_error);
+ ASSERT_THROW(l.try_lock_shared(), std::system_error);
+ }
+}