]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/seastar/include/seastar/core/semaphore.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / include / seastar / core / semaphore.hh
index a4837da0d50ec58470a54f73294639461d8ef588..2ed3d5ad60da8986e4a79c382275a497c615733b 100644 (file)
 #include <seastar/core/chunked_fifo.hh>
 #include <stdexcept>
 #include <exception>
+#include <optional>
 #include <seastar/core/timer.hh>
 #include <seastar/core/expiring_fifo.hh>
+#include <seastar/core/timed_out_error.hh>
 
 namespace seastar {
 
@@ -45,7 +47,7 @@ public:
 /// times out.
 ///
 /// \see semaphore::wait(typename timer<>::duration timeout, size_t nr)
-class semaphore_timed_out : public std::exception {
+class semaphore_timed_out : public timed_out_error {
 public:
     /// Reports the exception reason.
     virtual const char* what() const noexcept;
@@ -478,6 +480,31 @@ get_units(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units, typename
     });
 }
 
+/// \brief Try to take units from semaphore temporarily
+///
+/// Takes units from the semaphore, if available, and returns them when the \ref semaphore_units object goes out of scope.
+/// This provides a safe way to temporarily take units from a semaphore and ensure
+/// that they are eventually returned under all circumstances (exceptions, premature scope exits, etc).
+///
+/// Unlike with_semaphore(), the scope of unit holding is not limited to the scope of a single async lambda.
+///
+/// \param sem The semaphore to take units from
+/// \param units  Number of units to take
+/// \return an optional \ref semaphore_units object. If engaged, when the object goes out of scope or is reset
+///         the units are returned to the semaphore.
+///
+/// \note The caller must guarantee that \c sem is valid as long as
+///      \ref seaphore_units object is alive.
+///
+/// \related semaphore
+template<typename ExceptionFactory, typename Clock = typename timer<>::clock>
+std::optional<semaphore_units<ExceptionFactory, Clock>>
+try_get_units(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units) noexcept {
+    if (!sem.try_wait(units)) {
+        return std::nullopt;
+    }
+    return std::make_optional<semaphore_units<ExceptionFactory, Clock>>(sem, units);
+}
 
 /// \brief Consume units from semaphore temporarily
 ///
@@ -521,7 +548,7 @@ consume_units(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units) noexc
 /// \related semaphore
 template <typename ExceptionFactory, typename Func, typename Clock = typename timer<>::clock>
 inline
-futurize_t<std::result_of_t<Func()>>
+futurize_t<std::invoke_result_t<Func>>
 with_semaphore(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units, Func&& func) noexcept {
     return get_units(sem, units).then([func = std::forward<Func>(func)] (auto units) mutable {
         return futurize_invoke(std::forward<Func>(func)).finally([units = std::move(units)] {});
@@ -555,7 +582,7 @@ with_semaphore(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units, Func
 /// \related semaphore
 template <typename ExceptionFactory, typename Clock, typename Func>
 inline
-futurize_t<std::result_of_t<Func()>>
+futurize_t<std::invoke_result_t<Func>>
 with_semaphore(basic_semaphore<ExceptionFactory, Clock>& sem, size_t units, typename basic_semaphore<ExceptionFactory, Clock>::duration timeout, Func&& func) noexcept {
     return get_units(sem, units, timeout).then([func = std::forward<Func>(func)] (auto units) mutable {
         return futurize_invoke(std::forward<Func>(func)).finally([units = std::move(units)] {});