diff --git a/include/boost/fiber/condition_variable.hpp b/include/boost/fiber/condition_variable.hpp index fbb89a40..404917f0 100644 --- a/include/boost/fiber/condition_variable.hpp +++ b/include/boost/fiber/condition_variable.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #ifdef BOOST_HAS_ABI_HEADERS @@ -34,7 +35,7 @@ namespace fibers { using cv_status = std::cv_status; -class BOOST_FIBERS_DECL condition_variable { +class BOOST_FIBERS_DECL condition_variable_any { private: typedef context::wait_queue_t wait_queue_t; @@ -42,33 +43,24 @@ private: detail::spinlock wait_queue_splk_{}; public: - condition_variable() = default; + condition_variable_any() = default; - ~condition_variable() { + ~condition_variable_any() { BOOST_ASSERT( wait_queue_.empty() ); } - condition_variable( condition_variable const&) = delete; - condition_variable & operator=( condition_variable const&) = delete; + condition_variable_any( condition_variable_any const&) = delete; + condition_variable_any & operator=( condition_variable_any const&) = delete; void notify_one() noexcept; void notify_all() noexcept; - template< typename LockType, typename Pred > - void wait( LockType & lt, Pred pred) { - while ( ! pred() ) { - wait( lt); - } - } - template< typename LockType > void wait( LockType & lt) { // check if context was interrupted this_fiber::interruption_point(); context * ctx = context::active(); - // pre-conditions - BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_); // atomically call lt.unlock() and block on *this // store this fiber in waiting-queue detail::spinlock_lock lk( wait_queue_splk_); @@ -91,12 +83,18 @@ public: std::terminate(); } // post-conditions - BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_); BOOST_ASSERT( ! ctx->wait_is_linked() ); // check if context was interrupted this_fiber::interruption_point(); } + template< typename LockType, typename Pred > + void wait( LockType & lt, Pred pred) { + while ( ! pred() ) { + wait( lt); + } + } + template< typename LockType, typename Clock, typename Duration > cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) { // check if context was interrupted @@ -105,8 +103,6 @@ public: std::chrono::steady_clock::time_point timeout_time( detail::convert( timeout_time_) ); context * ctx = context::active(); - // pre-conditions - BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_); // atomically call lt.unlock() and block on *this // store this fiber in waiting-queue detail::spinlock_lock lk( wait_queue_splk_); @@ -131,7 +127,6 @@ public: std::terminate(); } // post-conditions - BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_); BOOST_ASSERT( ! ctx->wait_is_linked() ); // check if context was interrupted this_fiber::interruption_point(); @@ -163,7 +158,97 @@ public: } }; -using condition_variable_any = condition_variable; +class BOOST_FIBERS_DECL condition_variable { +private: + condition_variable_any cnd_; + +public: + condition_variable() = default; + + condition_variable( condition_variable const&) = delete; + condition_variable & operator=( condition_variable const&) = delete; + + void notify_one() noexcept { + cnd_.notify_one(); + } + + void notify_all() noexcept { + cnd_.notify_all(); + } + + void wait( std::unique_lock< mutex > & lt) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + cnd_.wait( lt); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + } + + template< typename Pred > + void wait( std::unique_lock< mutex > & lt, Pred pred) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + cnd_.wait( lt, pred); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + } + + template< typename Clock, typename Duration > + cv_status wait_until( std::unique_lock< mutex > & lt, + std::chrono::time_point< Clock, Duration > const& timeout_time) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + cv_status result = cnd_.wait_until( lt, timeout_time); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + return result; + } + + template< typename Clock, typename Duration, typename Pred > + bool wait_until( std::unique_lock< mutex > & lt, + std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + bool result = cnd_.wait_until( lt, timeout_time, pred); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + return result; + } + + template< typename Rep, typename Period > + cv_status wait_for( std::unique_lock< mutex > & lt, + std::chrono::duration< Rep, Period > const& timeout_duration) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + cv_status result = cnd_.wait_for( lt, timeout_duration); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + return result; + } + + template< typename Rep, typename Period, typename Pred > + bool wait_for( std::unique_lock< mutex > & lt, + std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) { + // pre-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + bool result = cnd_.wait_for( lt, timeout_duration, pred); + // post-condition + BOOST_ASSERT( lt.owns_lock() ); + BOOST_ASSERT( context::active() == lt.mutex()->owner_); + return result; + } +}; }} diff --git a/src/condition_variable.cpp b/src/condition_variable.cpp index a397056f..010891ab 100644 --- a/src/condition_variable.cpp +++ b/src/condition_variable.cpp @@ -16,7 +16,7 @@ namespace boost { namespace fibers { void -condition_variable::notify_one() noexcept { +condition_variable_any::notify_one() noexcept { // get one context' from wait-queue detail::spinlock_lock lk( wait_queue_splk_); if ( wait_queue_.empty() ) { @@ -29,7 +29,7 @@ condition_variable::notify_one() noexcept { } void -condition_variable::notify_all() noexcept { +condition_variable_any::notify_all() noexcept { // get all context' from wait-queue detail::spinlock_lock lk( wait_queue_splk_); // notify all context'