X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftest%2Fcommon%2Ftest_shunique_lock.cc;fp=src%2Fceph%2Fsrc%2Ftest%2Fcommon%2Ftest_shunique_lock.cc;h=77f9708259d2b5c42d936bfa3b59fae9164d42ab;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/test/common/test_shunique_lock.cc b/src/ceph/src/test/common/test_shunique_lock.cc new file mode 100644 index 0000000..77f9708 --- /dev/null +++ b/src/ceph/src/test/common/test_shunique_lock.cc @@ -0,0 +1,576 @@ +// -*- 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 +#include +#include + +#include + +#include "common/ceph_time.h" +#include "common/shunique_lock.h" + +#include "gtest/gtest.h" + +template +static bool test_try_lock(SharedMutex* sm) { + if (!sm->try_lock()) + return false; + sm->unlock(); + return true; +} + +template +static bool test_try_lock_shared(SharedMutex* sm) { + if (!sm->try_lock_shared()) + return false; + sm->unlock_shared(); + return true; +} + +template +static void check_conflicts(SharedMutex sm, AcquireType) { +} + +template +static void ensure_conflicts(SharedMutex& sm, ceph::acquire_unique_t) { + auto ttl = &test_try_lock; + auto ttls = &test_try_lock_shared; + ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get()); + ASSERT_FALSE(std::async(std::launch::async, ttls, &sm).get()); +} + +template +static void ensure_conflicts(SharedMutex& sm, ceph::acquire_shared_t) { + auto ttl = &test_try_lock; + auto ttls = &test_try_lock_shared; + ASSERT_FALSE(std::async(std::launch::async, ttl, &sm).get()); + ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get()); +} + +template +static void ensure_free(SharedMutex& sm) { + auto ttl = &test_try_lock; + auto ttls = &test_try_lock_shared; + ASSERT_TRUE(std::async(std::launch::async, ttl, &sm).get()); + ASSERT_TRUE(std::async(std::launch::async, ttls, &sm).get()); +} + +template +static void check_owns_lock(const SharedMutex& sm, + const ceph::shunique_lock& sul, + AcquireType) { +} + +template +static void check_owns_lock(const SharedMutex& sm, + const ceph::shunique_lock& sul, + ceph::acquire_unique_t) { + ASSERT_TRUE(sul.mutex() == &sm); + ASSERT_TRUE(sul.owns_lock()); + ASSERT_TRUE(!!sul); +} + +template +static void check_owns_lock(const SharedMutex& sm, + const ceph::shunique_lock& sul, + ceph::acquire_shared_t) { + ASSERT_TRUE(sul.owns_lock_shared()); + ASSERT_TRUE(!!sul); +} + +template +static void check_abjures_lock(const SharedMutex& sm, + const ceph::shunique_lock& sul) { + ASSERT_EQ(sul.mutex(), &sm); + ASSERT_FALSE(sul.owns_lock()); + ASSERT_FALSE(sul.owns_lock_shared()); + ASSERT_FALSE(!!sul); +} + +template +static void check_abjures_lock(const ceph::shunique_lock& 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 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 +void lock_unlock(AcquireType at) { + boost::shared_mutex sm; + typedef ceph::shunique_lock 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 +void lock_destruct(AcquireType at) { + boost::shared_mutex sm; + typedef ceph::shunique_lock 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 +void move_construct(AcquireType at) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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); + + boost::shared_mutex sm; + { + std::unique_lock ul(sm); + ensure_conflicts(sm, ceph::acquire_unique); + ceph::shunique_lock l(std::move(ul)); + check_owns_lock(sm, l, ceph::acquire_unique); + ensure_conflicts(sm, ceph::acquire_unique); + } + { + std::unique_lock ul(sm, std::defer_lock); + ensure_free(sm); + ceph::shunique_lock l(std::move(ul)); + check_abjures_lock(sm, l); + ensure_free(sm); + } + { + std::unique_lock ul; + ceph::shunique_lock l(std::move(ul)); + check_abjures_lock(l); + } + { + boost::shared_lock sl(sm); + ensure_conflicts(sm, ceph::acquire_shared); + ceph::shunique_lock l(std::move(sl)); + check_owns_lock(sm, l, ceph::acquire_shared); + ensure_conflicts(sm, ceph::acquire_shared); + } + { + boost::shared_lock sl; + ceph::shunique_lock l(std::move(sl)); + check_abjures_lock(l); + } +} + +template +void move_assign(AcquireType at) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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); + + boost::shared_mutex sm; + { + std::unique_lock ul(sm); + ensure_conflicts(sm, ceph::acquire_unique); + ceph::shunique_lock l; + l = std::move(ul); + check_owns_lock(sm, l, ceph::acquire_unique); + ensure_conflicts(sm, ceph::acquire_unique); + } + { + std::unique_lock ul(sm, std::defer_lock); + ensure_free(sm); + ceph::shunique_lock l; + l = std::move(ul); + check_abjures_lock(sm, l); + ensure_free(sm); + } + { + std::unique_lock ul; + ceph::shunique_lock l; + l = std::move(ul); + check_abjures_lock(l); + } + { + boost::shared_lock sl(sm); + ensure_conflicts(sm, ceph::acquire_shared); + ceph::shunique_lock l; + l = std::move(sl); + check_owns_lock(sm, l, ceph::acquire_shared); + ensure_conflicts(sm, ceph::acquire_shared); + } + { + boost::shared_lock sl; + ceph::shunique_lock l; + l = std::move(sl); + check_abjures_lock(l); + } + +} + +template +void construct_deferred(AcquireType at) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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 +void construct_try(AcquireType at) { + boost::shared_mutex sm; + typedef ceph::shunique_lock shunique_lock; + + { + shunique_lock l(sm, at, std::try_to_lock); + check_owns_lock(sm, l, at); + ensure_conflicts(sm, at); + } + + { + std::unique_lock 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 +void construct_adopt(AcquireType at) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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 +void try_lock(AcquireType at) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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 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) { + boost::shared_mutex sm; + typedef ceph::shunique_lock 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 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 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) { + boost::shared_mutex sm; + + typedef ceph::shunique_lock 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); + } +}