diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/common/async/shared_mutex.h | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/common/async/shared_mutex.h')
-rw-r--r-- | src/common/async/shared_mutex.h | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/common/async/shared_mutex.h b/src/common/async/shared_mutex.h new file mode 100644 index 000000000..3e471a4df --- /dev/null +++ b/src/common/async/shared_mutex.h @@ -0,0 +1,212 @@ +// -*- 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) 2018 Red Hat + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include "common/async/detail/shared_mutex.h" + +namespace ceph::async { + +/** + * An asynchronous shared mutex for use with boost::asio. + * + * A shared mutex class with asynchronous lock operations that complete on a + * boost::asio executor. The class also has synchronous interfaces that meet + * most of the standard library's requirements for the SharedMutex concept, + * which makes it compatible with lock_guard, unique_lock, and shared_lock. + * + * All lock requests can fail with operation_aborted on cancel() or destruction. + * The non-error_code overloads of lock() and lock_shared() will throw this + * error as an exception of type boost::system::system_error. + * + * Exclusive locks are prioritized over shared locks. Locks of the same type + * are granted in fifo order. The implementation defines a limit on the number + * of shared locks to 65534 at a time. + * + * Example use: + * + * boost::asio::io_context context; + * SharedMutex mutex{context.get_executor()}; + * + * mutex.async_lock([&] (boost::system::error_code ec, auto lock) { + * if (!ec) { + * // mutate shared state ... + * } + * }); + * mutex.async_lock_shared([&] (boost::system::error_code ec, auto lock) { + * if (!ec) { + * // read shared state ... + * } + * }); + * + * context.run(); + */ +template <typename Executor> +class SharedMutex { + public: + explicit SharedMutex(const Executor& ex); + + /// on destruction, all pending lock requests are canceled + ~SharedMutex(); + + using executor_type = Executor; + executor_type get_executor() const noexcept { return ex; } + + /// initiate an asynchronous request for an exclusive lock. when the lock is + /// granted, the completion handler is invoked with a successful error code + /// and a std::unique_lock that owns this mutex. + /// Signature = void(boost::system::error_code, std::unique_lock) + template <typename CompletionToken> + auto async_lock(CompletionToken&& token); + + /// wait synchronously for an exclusive lock. if an error occurs before the + /// lock is granted, that error is thrown as an exception + void lock(); + + /// wait synchronously for an exclusive lock. if an error occurs before the + /// lock is granted, that error is assigned to 'ec' + void lock(boost::system::error_code& ec); + + /// try to acquire an exclusive lock. if the lock is not immediately + /// available, returns false + bool try_lock(); + + /// releases an exclusive lock. not required to be called from the same thread + /// that initiated the lock + void unlock(); + + /// initiate an asynchronous request for a shared lock. when the lock is + /// granted, the completion handler is invoked with a successful error code + /// and a std::shared_lock that owns this mutex. + /// Signature = void(boost::system::error_code, std::shared_lock) + template <typename CompletionToken> + auto async_lock_shared(CompletionToken&& token); + + /// wait synchronously for a shared lock. if an error occurs before the + /// lock is granted, that error is thrown as an exception + void lock_shared(); + + /// wait synchronously for a shared lock. if an error occurs before the lock + /// is granted, that error is assigned to 'ec' + void lock_shared(boost::system::error_code& ec); + + /// try to acquire a shared lock. if the lock is not immediately available, + /// returns false + bool try_lock_shared(); + + /// releases a shared lock. not required to be called from the same thread + /// that initiated the lock + void unlock_shared(); + + /// cancel any pending requests for exclusive or shared locks with an + /// operation_aborted error + void cancel(); + + private: + Executor ex; //< default callback executor + boost::intrusive_ptr<detail::SharedMutexImpl> impl; + + // allow lock guards to access impl + friend class std::unique_lock<SharedMutex>; + friend class std::shared_lock<SharedMutex>; +}; + + +template <typename Executor> +SharedMutex<Executor>::SharedMutex(const Executor& ex) + : ex(ex), impl(new detail::SharedMutexImpl) +{ +} + +template <typename Executor> +SharedMutex<Executor>::~SharedMutex() +{ + try { + impl->cancel(); + } catch (const std::exception&) { + // swallow any exceptions, the destructor can't throw + } +} + +template <typename Executor> +template <typename CompletionToken> +auto SharedMutex<Executor>::async_lock(CompletionToken&& token) +{ + return impl->async_lock(*this, std::forward<CompletionToken>(token)); +} + +template <typename Executor> +void SharedMutex<Executor>::lock() +{ + impl->lock(); +} + +template <typename Executor> +void SharedMutex<Executor>::lock(boost::system::error_code& ec) +{ + impl->lock(ec); +} + +template <typename Executor> +bool SharedMutex<Executor>::try_lock() +{ + return impl->try_lock(); +} + +template <typename Executor> +void SharedMutex<Executor>::unlock() +{ + impl->unlock(); +} + +template <typename Executor> +template <typename CompletionToken> +auto SharedMutex<Executor>::async_lock_shared(CompletionToken&& token) +{ + return impl->async_lock_shared(*this, std::forward<CompletionToken>(token)); +} + +template <typename Executor> +void SharedMutex<Executor>::lock_shared() +{ + impl->lock_shared(); +} + +template <typename Executor> +void SharedMutex<Executor>::lock_shared(boost::system::error_code& ec) +{ + impl->lock_shared(ec); +} + +template <typename Executor> +bool SharedMutex<Executor>::try_lock_shared() +{ + return impl->try_lock_shared(); +} + +template <typename Executor> +void SharedMutex<Executor>::unlock_shared() +{ + impl->unlock_shared(); +} + +template <typename Executor> +void SharedMutex<Executor>::cancel() +{ + impl->cancel(); +} + +} // namespace ceph::async + +#include "common/async/detail/shared_lock.h" |