X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fshunique_lock.h;fp=src%2Fceph%2Fsrc%2Fcommon%2Fshunique_lock.h;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=b7ad08cc10af649f1100fc6460eb89f822db3f61;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/common/shunique_lock.h b/src/ceph/src/common/shunique_lock.h deleted file mode 100644 index b7ad08c..0000000 --- a/src/ceph/src/common/shunique_lock.h +++ /dev/null @@ -1,395 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef CEPH_COMMON_SHUNIQUE_LOCK_H -#define CEPH_COMMON_SHUNIQUE_LOCK_H - -#include -#include -#include - -namespace ceph { -// This is a 'lock' class in the style of shared_lock and -// unique_lock. Like shared_mutex it implements both Lockable and -// SharedLockable. - -// My rationale is thus: one of the advantages of unique_lock is that -// I can pass a thread of execution's control of a lock around as a -// parameter. So that methods further down the call stack can unlock -// it, do something, relock it, and have the lock state be known by -// the caller afterward, explicitly. The shared_lock class offers a -// similar advantage to shared_lock, but each class is one or the -// other. In Objecter we have calls that in most cases need /a/ lock -// on the shared mutex, and whether it's shared or exclusive doesn't -// matter. In some circumstances they may drop the shared lock and -// reacquire an exclusive one. This could be handled by passing both a -// shared and unique lock down the call stack. This is vexacious and -// shameful. - -// Wanting to avoid heaping shame and vexation upon myself, I threw -// this class together. - -// This class makes no attempt to support atomic upgrade or -// downgrade. I don't want either. Matt has convinced me that if you -// think you want them you've usually made a mistake somewhere. It is -// exactly and only a reification of the state held on a shared mutex. - -/// Acquire unique ownership of the mutex. -struct acquire_unique_t { }; - -/// Acquire shared ownership of the mutex. -struct acquire_shared_t { }; - -constexpr acquire_unique_t acquire_unique { }; -constexpr acquire_shared_t acquire_shared { }; - -template -class shunique_lock { -public: - typedef Mutex mutex_type; - typedef std::unique_lock unique_lock_type; - typedef boost::shared_lock shared_lock_type; - - shunique_lock() noexcept : m(nullptr), o(ownership::none) { } - - // We do not provide a default locking/try_locking constructor that - // takes only the mutex, since it is not clear whether to take it - // shared or unique. We explicitly require the use of lock_deferred - // to prevent Nasty Surprises. - - shunique_lock(mutex_type& m, std::defer_lock_t) noexcept - : m(&m), o(ownership::none) { } - - shunique_lock(mutex_type& m, acquire_unique_t) - : m(&m), o(ownership::none) { - lock(); - } - - shunique_lock(mutex_type& m, acquire_shared_t) - : m(&m), o(ownership::none) { - lock_shared(); - } - - template - shunique_lock(mutex_type& m, AcquireType at, std::try_to_lock_t) - : m(&m), o(ownership::none) { - try_lock(at); - } - - shunique_lock(mutex_type& m, acquire_unique_t, std::adopt_lock_t) - : m(&m), o(ownership::unique) { - // You'd better actually have a lock, or I will find you and I - // will hunt you down. - } - - shunique_lock(mutex_type& m, acquire_shared_t, std::adopt_lock_t) - : m(&m), o(ownership::shared) { - } - - template - shunique_lock(mutex_type& m, AcquireType at, - const std::chrono::time_point& t) - : m(&m), o(ownership::none) { - try_lock_until(at, t); - } - - template - shunique_lock(mutex_type& m, AcquireType at, - const std::chrono::duration& dur) - : m(&m), o(ownership::none) { - try_lock_for(at, dur); - } - - ~shunique_lock() { - switch (o) { - case ownership::none: - return; - break; - case ownership::unique: - m->unlock(); - break; - case ownership::shared: - m->unlock_shared(); - break; - } - } - - shunique_lock(shunique_lock const&) = delete; - shunique_lock& operator=(shunique_lock const&) = delete; - - shunique_lock(shunique_lock&& l) noexcept : shunique_lock() { - swap(l); - } - - shunique_lock(unique_lock_type&& l) noexcept { - if (l.owns_lock()) - o = ownership::unique; - else - o = ownership::none; - m = l.release(); - } - - shunique_lock(shared_lock_type&& l) noexcept { - if (l.owns_lock()) - o = ownership::shared; - else - o = ownership::none; - m = l.release(); - } - - shunique_lock& operator=(shunique_lock&& l) noexcept { - shunique_lock(std::move(l)).swap(*this); - return *this; - } - - shunique_lock& operator=(unique_lock_type&& l) noexcept { - shunique_lock(std::move(l)).swap(*this); - return *this; - } - - shunique_lock& operator=(shared_lock_type&& l) noexcept { - shunique_lock(std::move(l)).swap(*this); - return *this; - } - - void lock() { - lockable(); - m->lock(); - o = ownership::unique; - } - - void lock_shared() { - lockable(); - m->lock_shared(); - o = ownership::shared; - } - - void lock(ceph::acquire_unique_t) { - lock(); - } - - void lock(ceph::acquire_shared_t) { - lock_shared(); - } - - bool try_lock() { - lockable(); - if (m->try_lock()) { - o = ownership::unique; - return true; - } - return false; - } - - bool try_lock_shared() { - lockable(); - if (m->try_lock_shared()) { - o = ownership::shared; - return true; - } - return false; - } - - bool try_lock(ceph::acquire_unique_t) { - return try_lock(); - } - - bool try_lock(ceph::acquire_shared_t) { - return try_lock_shared(); - } - - template - bool try_lock_for(const std::chrono::duration& dur) { - lockable(); - if (m->try_lock_for(dur)) { - o = ownership::unique; - return true; - } - return false; - } - - template - bool try_lock_shared_for(const std::chrono::duration& dur) { - lockable(); - if (m->try_lock_shared_for(dur)) { - o = ownership::shared; - return true; - } - return false; - } - - template - bool try_lock_for(ceph::acquire_unique_t, - const std::chrono::duration& dur) { - return try_lock_for(dur); - } - - template - bool try_lock_for(ceph::acquire_shared_t, - const std::chrono::duration& dur) { - return try_lock_shared_for(dur); - } - - template - bool try_lock_until(const std::chrono::time_point& time) { - lockable(); - if (m->try_lock_until(time)) { - o = ownership::unique; - return true; - } - return false; - } - - template - bool try_lock_shared_until(const std::chrono::time_point& time) { - lockable(); - if (m->try_lock_shared_until(time)) { - o = ownership::shared; - return true; - } - return false; - } - - template - bool try_lock_until(ceph::acquire_unique_t, - const std::chrono::time_point& time) { - return try_lock_until(time); - } - - template - bool try_lock_until(ceph::acquire_shared_t, - const std::chrono::time_point& time) { - return try_lock_shared_until(time); - } - - // Only have a single unlock method. Otherwise we'd be building an - // Acme lock class suitable only for ravenous coyotes desparate to - // devour a road runner. It would be bad. It would be disgusting. It - // would be infelicitous as heck. It would leave our developers in a - // state of seeming safety unaware of the yawning chasm of failure - // that had opened beneath their feet that would soon transition - // into a sickening realization of the error they made and a brief - // moment of blinking self pity before their program hurled itself - // into undefined behaviour and plummeted up the stack with core - // dumps trailing behind it. - - void unlock() { - switch (o) { - case ownership::none: - throw std::system_error((int)std::errc::resource_deadlock_would_occur, - std::generic_category()); - break; - - case ownership::unique: - m->unlock(); - break; - - case ownership::shared: - m->unlock_shared(); - break; - } - o = ownership::none; - } - - // Setters - - void swap(shunique_lock& u) noexcept { - std::swap(m, u.m); - std::swap(o, u.o); - } - - mutex_type* release() noexcept { - o = ownership::none; - mutex_type* tm = m; - m = nullptr; - return tm; - } - - // Ideally I'd rather make a move constructor for std::unique_lock - // that took a shunique_lock, but obviously I can't. - unique_lock_type release_to_unique() { - if (o == ownership::unique) { - o = ownership::none; - unique_lock_type tu(*m, std::adopt_lock); - m = nullptr; - return tu; - } else if (o == ownership::none) { - unique_lock_type tu(*m, std::defer_lock); - m = nullptr; - return tu; - } else if (m == nullptr) { - return unique_lock_type(); - } - throw std::system_error((int)std::errc::operation_not_permitted, - std::generic_category()); - return unique_lock_type(); - } - - shared_lock_type release_to_shared() { - if (o == ownership::shared) { - o = ownership::none; - shared_lock_type ts(*m, std::adopt_lock); - m = nullptr; - return ts; - } else if (o == ownership::none) { - shared_lock_type ts(*m, std::defer_lock); - m = nullptr; - return ts; - } else if (m == nullptr) { - return shared_lock_type(); - } - throw std::system_error((int)std::errc::operation_not_permitted, - std::generic_category()); - return shared_lock_type(); - } - - // Getters - - // Note that this returns true if the lock UNIQUE, it will return - // false for shared - bool owns_lock() const noexcept { - return o == ownership::unique; - } - - bool owns_lock_shared() const noexcept { - return o == ownership::shared; - } - - // If you want to make sure you have a lock of some sort on the - // mutex, just treat as a bool. - explicit operator bool() const noexcept { - return o != ownership::none; - } - - mutex_type* mutex() const noexcept { - return m; - } - -private: - void lockable() const { - if (m == nullptr) - throw std::system_error((int)std::errc::operation_not_permitted, - std::generic_category()); - if (o != ownership::none) - throw std::system_error((int)std::errc::resource_deadlock_would_occur, - std::generic_category()); - } - - mutex_type* m; - enum struct ownership : uint8_t { - none, unique, shared - }; - ownership o; -}; -} // namespace ceph - -namespace std { - template - void swap(ceph::shunique_lock sh1, - ceph::shunique_lock sha) { - sh1.swap(sha); - } -} // namespace std - -#endif // CEPH_COMMON_SHUNIQUE_LOCK_H