diff --git a/include/foonathan/memory/allocator_storage.hpp b/include/foonathan/memory/allocator_storage.hpp index 0fe37fa..cf65705 100644 --- a/include/foonathan/memory/allocator_storage.hpp +++ b/include/foonathan/memory/allocator_storage.hpp @@ -313,6 +313,20 @@ namespace foonathan { return StoragePolicy::is_composable(); } + + /// @{ + /// \effects Explicitly unlocks the \c Mutex. + /// \returns the result of force_unlock() on \c Mutex. + /// \note Only available if \c Mutex supports force_unlock(). + /// \note Calling this function can be dangerous, but may be + /// necessary in certain situations (like forcing an allocator + /// to be unlocked in an atfork child handler). + template + auto force_unlock() noexcept -> decltype(std::declval()->force_unlock()) + { + return static_cast(*this)->force_unlock(); + } + /// @} }; /// Tag type that enables type-erasure in \ref reference_storage. diff --git a/include/foonathan/memory/threading.hpp b/include/foonathan/memory/threading.hpp index 059e3b4..5665723 100644 --- a/include/foonathan/memory/threading.hpp +++ b/include/foonathan/memory/threading.hpp @@ -33,6 +33,7 @@ namespace foonathan } void unlock() noexcept {} + void force_unlock() noexcept {} }; /// Specifies whether or not a \concept{concept_rawallocator,RawAllocator} is thread safe as-is. @@ -79,6 +80,11 @@ namespace foonathan mutex_.unlock(); } + Mutex * operator->() const noexcept + { + return std::addressof(mutex_); + } + protected: ~mutex_storage() noexcept = default; @@ -94,6 +100,12 @@ namespace foonathan void lock() const noexcept {} void unlock() const noexcept {} + void force_unlock() const noexcept {} + + mutex_storage const * operator->() const noexcept + { + return this; + } protected: ~mutex_storage() noexcept = default;