diff options
Diffstat (limited to 'src/common/fair_mutex.h')
-rw-r--r-- | src/common/fair_mutex.h | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/common/fair_mutex.h b/src/common/fair_mutex.h new file mode 100644 index 000000000..9baa04400 --- /dev/null +++ b/src/common/fair_mutex.h @@ -0,0 +1,80 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- + +#pragma once + +#include "common/ceph_mutex.h" + +#include <thread> +#include <string> + +namespace ceph { +/// a FIFO mutex +class fair_mutex { +public: + fair_mutex(const std::string& name) + : mutex{ceph::make_mutex(name)} + {} + ~fair_mutex() = default; + fair_mutex(const fair_mutex&) = delete; + fair_mutex& operator=(const fair_mutex&) = delete; + + void lock() + { + std::unique_lock lock(mutex); + const unsigned my_id = next_id++; + cond.wait(lock, [&] { + return my_id == unblock_id; + }); + _set_locked_by(); + } + + bool try_lock() + { + std::lock_guard lock(mutex); + if (is_locked()) { + return false; + } + ++next_id; + _set_locked_by(); + return true; + } + + void unlock() + { + std::lock_guard lock(mutex); + ++unblock_id; + _reset_locked_by(); + cond.notify_all(); + } + + bool is_locked() const + { + return next_id != unblock_id; + } + +#ifdef CEPH_DEBUG_MUTEX + bool is_locked_by_me() const { + return is_locked() && locked_by == std::this_thread::get_id(); + } +private: + void _set_locked_by() { + locked_by = std::this_thread::get_id(); + } + void _reset_locked_by() { + locked_by = {}; + } +#else + void _set_locked_by() {} + void _reset_locked_by() {} +#endif + +private: + unsigned next_id = 0; + unsigned unblock_id = 0; + ceph::condition_variable cond; + ceph::mutex mutex; +#ifdef CEPH_DEBUG_MUTEX + std::thread::id locked_by = {}; +#endif +}; +} // namespace ceph |