diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/test/common/test_shunique_lock.cc | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/common/test_shunique_lock.cc')
-rw-r--r-- | src/test/common/test_shunique_lock.cc | 575 |
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); + } +} |