From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/common/async/shared_mutex.h | 212 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 src/common/async/shared_mutex.h (limited to 'src/common/async/shared_mutex.h') 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 +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 + 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 + 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 impl; + + // allow lock guards to access impl + friend class std::unique_lock; + friend class std::shared_lock; +}; + + +template +SharedMutex::SharedMutex(const Executor& ex) + : ex(ex), impl(new detail::SharedMutexImpl) +{ +} + +template +SharedMutex::~SharedMutex() +{ + try { + impl->cancel(); + } catch (const std::exception&) { + // swallow any exceptions, the destructor can't throw + } +} + +template +template +auto SharedMutex::async_lock(CompletionToken&& token) +{ + return impl->async_lock(*this, std::forward(token)); +} + +template +void SharedMutex::lock() +{ + impl->lock(); +} + +template +void SharedMutex::lock(boost::system::error_code& ec) +{ + impl->lock(ec); +} + +template +bool SharedMutex::try_lock() +{ + return impl->try_lock(); +} + +template +void SharedMutex::unlock() +{ + impl->unlock(); +} + +template +template +auto SharedMutex::async_lock_shared(CompletionToken&& token) +{ + return impl->async_lock_shared(*this, std::forward(token)); +} + +template +void SharedMutex::lock_shared() +{ + impl->lock_shared(); +} + +template +void SharedMutex::lock_shared(boost::system::error_code& ec) +{ + impl->lock_shared(ec); +} + +template +bool SharedMutex::try_lock_shared() +{ + return impl->try_lock_shared(); +} + +template +void SharedMutex::unlock_shared() +{ + impl->unlock_shared(); +} + +template +void SharedMutex::cancel() +{ + impl->cancel(); +} + +} // namespace ceph::async + +#include "common/async/detail/shared_lock.h" -- cgit v1.2.3