From 2002dba9d38410934122b82a830fec2de47b3dd8 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 16 Jun 2015 18:49:28 +0200 Subject: [PATCH] enable/disable atomic<> with BOOST_FIBERS_THREADSAFE --- include/boost/fiber/condition.hpp | 24 +++++++- include/boost/fiber/fiber_context.hpp | 58 +++++++++++++++---- include/boost/fiber/fiber_manager.hpp | 26 ++++++++- include/boost/fiber/fss.hpp | 1 - include/boost/fiber/mutex.hpp | 6 +- include/boost/fiber/operations.hpp | 8 ++- include/boost/fiber/recursive_mutex.hpp | 6 +- include/boost/fiber/recursive_timed_mutex.hpp | 6 +- include/boost/fiber/timed_mutex.hpp | 6 +- src/condition.cpp | 15 +++++ src/fiber_context.cpp | 6 ++ src/fiber_manager.cpp | 31 +++++++++- src/mutex.cpp | 17 ++++++ src/recursive_mutex.cpp | 17 ++++++ src/recursive_timed_mutex.cpp | 31 ++++++++++ src/timed_mutex.cpp | 31 ++++++++++ test/test_condition_mt.cpp | 6 ++ test/test_futures_mt.cpp | 6 ++ test/test_mutex_mt.cpp | 6 ++ 19 files changed, 284 insertions(+), 23 deletions(-) diff --git a/include/boost/fiber/condition.hpp b/include/boost/fiber/condition.hpp index 6feca7c1..6d35dbb5 100644 --- a/include/boost/fiber/condition.hpp +++ b/include/boost/fiber/condition.hpp @@ -17,7 +17,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #include #include @@ -38,7 +40,9 @@ enum class cv_status { class BOOST_FIBERS_DECL condition { private: +#if defined(BOOST_FIBERS_THREADSAFE) detail::spinlock splk_; +#endif std::deque< fiber_context * > waiting_; public: @@ -64,8 +68,10 @@ public: void wait( LockType & lt) { fiber_context * f( detail::scheduler::instance()->active() ); try { +#if defined(BOOST_FIBERS_THREADSAFE) // lock spinlock std::unique_lock< detail::spinlock > lk( splk_); +#endif BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); // store this fiber in waiting-queue @@ -76,9 +82,13 @@ public: lt.unlock(); // suspend this fiber +#if defined(BOOST_FIBERS_THREADSAFE) // locked spinlock will be released if this fiber // was stored inside schedulers's waiting-queue detail::scheduler::instance()->wait( lk); +#else + detail::scheduler::instance()->wait(); +#endif // this fiber was notified and resumed // check if fiber was interrupted @@ -87,7 +97,9 @@ public: // lock external again before returning lt.lock(); } catch (...) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif std::deque< fiber_context * >::iterator i( std::find( waiting_.begin(), waiting_.end(), f) ); if ( waiting_.end() != i) { // remove fiber from waiting-list @@ -104,8 +116,10 @@ public: fiber_context * f( detail::scheduler::instance()->active() ); try { +#if defined(BOOST_FIBERS_THREADSAFE) // lock spinlock std::unique_lock< detail::spinlock > lk( splk_); +#endif // store this fiber in waiting-queue // in order notify (resume) this fiber later @@ -117,10 +131,16 @@ public: // suspend this fiber // locked spinlock will be released if this fiber // was stored inside schedulers's waiting-queue +#if defined(BOOST_FIBERS_THREADSAFE) if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) { +#else + if ( ! detail::scheduler::instance()->wait_until( timeout_time) ) { +#endif // this fiber was not notified before timeout +#if defined(BOOST_FIBERS_THREADSAFE) // lock spinlock again std::unique_lock< detail::spinlock > lk( splk_); +#endif std::deque< fiber_context * >::iterator i( std::find( waiting_.begin(), waiting_.end(), f) ); if ( waiting_.end() != i) { // remove fiber from waiting-list @@ -136,7 +156,9 @@ public: // lock external again before returning lt.lock(); } catch (...) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif std::deque< fiber_context * >::iterator i( std::find( waiting_.begin(), waiting_.end(), f) ); if ( waiting_.end() != i) { // remove fiber from waiting-list diff --git a/include/boost/fiber/fiber_context.hpp b/include/boost/fiber/fiber_context.hpp index 953e83b8..f3b577f4 100644 --- a/include/boost/fiber/fiber_context.hpp +++ b/include/boost/fiber/fiber_context.hpp @@ -24,7 +24,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #include #include @@ -77,12 +79,18 @@ private: typedef std::map< uintptr_t, fss_data > fss_data_t; +#if defined(BOOST_FIBERS_THREADSAFE) std::atomic< std::size_t > use_count_; - context::execution_context ctx_; - fss_data_t fss_data_; std::atomic< fiber_status > state_; std::atomic< int > flags_; detail::spinlock splk_; +#else + std::size_t use_count_; + fiber_status state_; + int flags_; +#endif + context::execution_context ctx_; + fss_data_t fss_data_; std::vector< fiber_context * > waiting_; std::exception_ptr except_; std::chrono::high_resolution_clock::time_point tp_; @@ -91,15 +99,18 @@ private: // main fiber fiber_context() : use_count_( 1), // allocated on stack - ctx_( context::execution_context::current() ), - fss_data_(), state_( fiber_status::running), flags_( flag_main_fiber), +#if defined(BOOST_FIBERS_THREADSAFE) + splk_(), +#endif + ctx_( context::execution_context::current() ), + fss_data_(), waiting_(), except_(), tp_( (std::chrono::high_resolution_clock::time_point::max)() ), properties_( nullptr), - nxt() { + nxt( nullptr) { } // worker fiber @@ -108,6 +119,11 @@ private: Fn && fn_, Tpl && tpl_, std::index_sequence< I ... >) : use_count_( 1), // allocated on stack + state_( fiber_status::ready), + flags_( 0), +#if defined(BOOST_FIBERS_THREADSAFE) + splk_(), +#endif ctx_( palloc, salloc, [=,fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable { try { @@ -135,8 +151,6 @@ private: BOOST_ASSERT_MSG( false, "fiber already terminated"); }), fss_data_(), - state_( fiber_status::ready), - flags_( 0), waiting_(), except_(), tp_( (std::chrono::high_resolution_clock::time_point::max)() ), @@ -228,13 +242,13 @@ public: bool join( fiber_context *); bool interruption_blocked() const noexcept { - return 0 != ( flags_.load() & flag_interruption_blocked); + return 0 != ( flags_ & flag_interruption_blocked); } void interruption_blocked( bool blck) noexcept; bool interruption_requested() const noexcept { - return 0 != ( flags_.load() & flag_interruption_requested); + return 0 != ( flags_ & flag_interruption_requested); } void request_interruption( bool req) noexcept; @@ -256,25 +270,49 @@ public: } void set_terminated() noexcept { + // TODO +#if defined(BOOST_FIBERS_THREADSAFE) fiber_status previous = state_.exchange( fiber_status::terminated); +#else + fiber_status previous = state_; + state_ = fiber_status::terminated; +#endif BOOST_ASSERT( fiber_status::running == previous); (void)previous; } void set_ready() noexcept { + // TODO +#if defined(BOOST_FIBERS_THREADSAFE) fiber_status previous = state_.exchange( fiber_status::ready); +#else + fiber_status previous = state_; + state_ = fiber_status::ready; +#endif BOOST_ASSERT( fiber_status::waiting == previous || fiber_status::running == previous || fiber_status::ready == previous); (void)previous; } void set_running() noexcept { + // TODO +#if defined(BOOST_FIBERS_THREADSAFE) fiber_status previous = state_.exchange( fiber_status::running); +#else + fiber_status previous = state_; + state_ = fiber_status::running; +#endif BOOST_ASSERT( fiber_status::ready == previous); (void)previous; } void set_waiting() noexcept { + // TODO +#if defined(BOOST_FIBERS_THREADSAFE) fiber_status previous = state_.exchange( fiber_status::waiting); +#else + fiber_status previous = state_; + state_ = fiber_status::waiting; +#endif BOOST_ASSERT( fiber_status::running == previous); (void)previous; } diff --git a/include/boost/fiber/fiber_manager.hpp b/include/boost/fiber/fiber_manager.hpp index c77561fe..596848ec 100644 --- a/include/boost/fiber/fiber_manager.hpp +++ b/include/boost/fiber/fiber_manager.hpp @@ -14,7 +14,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #include @@ -56,6 +58,7 @@ public: void run(); +#if defined(BOOST_FIBERS_THREADSAFE) void wait( std::unique_lock< detail::spinlock > &); bool wait_until( std::chrono::high_resolution_clock::time_point const&, @@ -63,7 +66,7 @@ public: template< typename Clock, typename Duration > bool wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time_, - std::unique_lock< detail::spinlock > & lk) { + std::unique_lock< detail::spinlock > & lk) { std::chrono::high_resolution_clock::time_point timeout_time( detail::convert_tp( timeout_time_) ); return wait_until( timeout_time, lk); @@ -71,9 +74,26 @@ public: template< typename Rep, typename Period > bool wait_for( std::chrono::duration< Rep, Period > const& timeout_duration, - std::unique_lock< detail::spinlock > & lk) { + std::unique_lock< detail::spinlock > & lk) { return wait_until( std::chrono::high_resolution_clock::now() + timeout_duration, lk); } +#else + void wait(); + + bool wait_until( std::chrono::high_resolution_clock::time_point const&); + + template< typename Clock, typename Duration > + bool wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time_) { + std::chrono::high_resolution_clock::time_point timeout_time( + detail::convert_tp( timeout_time_) ); + return wait_until( timeout_time); + } + + template< typename Rep, typename Period > + bool wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) { + return wait_until( std::chrono::high_resolution_clock::now() + timeout_duration); + } +#endif void yield(); diff --git a/include/boost/fiber/fss.hpp b/include/boost/fiber/fss.hpp index 339e11a2..5329e289 100644 --- a/include/boost/fiber/fss.hpp +++ b/include/boost/fiber/fss.hpp @@ -9,7 +9,6 @@ #ifndef BOOST_FIBERS_FSS_H #define BOOST_FIBERS_FSS_H -#include #include #include diff --git a/include/boost/fiber/mutex.hpp b/include/boost/fiber/mutex.hpp index 1c449a53..53326644 100644 --- a/include/boost/fiber/mutex.hpp +++ b/include/boost/fiber/mutex.hpp @@ -12,7 +12,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #ifdef BOOST_HAS_ABI_HEADERS @@ -29,7 +31,9 @@ private: unlocked }; +#if defined(BOOST_FIBERS_THREADSAFE) detail::spinlock splk_; +#endif mutex_status state_; fiber_context::id owner_; std::deque< fiber_context * > waiting_; diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp index f79a8236..139bc3f8 100644 --- a/include/boost/fiber/operations.hpp +++ b/include/boost/fiber/operations.hpp @@ -13,7 +13,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #include @@ -36,9 +38,13 @@ void yield() { template< typename Clock, typename Duration > void sleep_until( std::chrono::time_point< Clock, Duration > const& sleep_time) { +#if defined(BOOST_FIBERS_THREADSAFE) fibers::detail::spinlock splk; std::unique_lock< fibers::detail::spinlock > lk( splk); fibers::detail::scheduler::instance()->wait_until( sleep_time, lk); +#else + fibers::detail::scheduler::instance()->wait_until( sleep_time); +#endif // check if fiber was interrupted interruption_point(); diff --git a/include/boost/fiber/recursive_mutex.hpp b/include/boost/fiber/recursive_mutex.hpp index e658ee1f..822aba98 100644 --- a/include/boost/fiber/recursive_mutex.hpp +++ b/include/boost/fiber/recursive_mutex.hpp @@ -15,7 +15,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #ifdef BOOST_HAS_ABI_HEADERS @@ -32,7 +34,9 @@ private: unlocked }; +#if defined(BOOST_FIBERS_THREADSAFE) detail::spinlock splk_; +#endif mutex_status state_; fiber_context::id owner_; std::size_t count_; diff --git a/include/boost/fiber/recursive_timed_mutex.hpp b/include/boost/fiber/recursive_timed_mutex.hpp index 6214c96e..80f1f4ca 100644 --- a/include/boost/fiber/recursive_timed_mutex.hpp +++ b/include/boost/fiber/recursive_timed_mutex.hpp @@ -17,7 +17,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #ifdef BOOST_HAS_ABI_HEADERS @@ -34,7 +36,9 @@ private: unlocked }; +#if defined(BOOST_FIBERS_THREADSAFE) detail::spinlock splk_; +#endif mutex_status state_; fiber_context::id owner_; std::size_t count_; diff --git a/include/boost/fiber/timed_mutex.hpp b/include/boost/fiber/timed_mutex.hpp index ef661f30..636b07dd 100644 --- a/include/boost/fiber/timed_mutex.hpp +++ b/include/boost/fiber/timed_mutex.hpp @@ -14,7 +14,9 @@ #include #include -#include +#if defined(BOOST_FIBERS_THREADSAFE) +# include +#endif #include #ifdef BOOST_HAS_ABI_HEADERS @@ -31,7 +33,9 @@ private: unlocked }; +#if defined(BOOST_FIBERS_THREADSAFE) detail::spinlock splk_; +#endif mutex_status state_; fiber_context::id owner_; std::deque< fiber_context * > waiting_; diff --git a/src/condition.cpp b/src/condition.cpp index 35c57a5a..b1ccc5f2 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -16,7 +16,9 @@ namespace boost { namespace fibers { condition::condition() : +#if defined(BOOST_FIBERS_THREADSAFE) splk_(), +#endif waiting_() { } @@ -28,6 +30,7 @@ void condition::notify_one() { fiber_context * f( nullptr); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); // get one waiting fiber if ( ! waiting_.empty() ) { @@ -35,6 +38,13 @@ condition::notify_one() { waiting_.pop_front(); } lk.unlock(); +#else + // get one waiting fiber + if ( ! waiting_.empty() ) { + f = waiting_.front(); + waiting_.pop_front(); + } +#endif // notify waiting fiber if ( nullptr != f) { @@ -46,10 +56,15 @@ void condition::notify_all() { std::deque< fiber_context * > waiting; +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); // get all waiting fibers waiting.swap( waiting_); lk.unlock(); +#else + // get all waiting fibers + waiting.swap( waiting_); +#endif // notify all waiting fibers while ( ! waiting.empty() ) { diff --git a/src/fiber_context.cpp b/src/fiber_context.cpp index 32f25ece..5fa64bda 100644 --- a/src/fiber_context.cpp +++ b/src/fiber_context.cpp @@ -35,9 +35,13 @@ fiber_context::release() { std::vector< fiber_context * > waiting; // get all waiting fibers +#if defined(BOOST_FIBERS_THREADSAFE) splk_.lock(); waiting.swap( waiting_); splk_.unlock(); +#else + waiting.swap( waiting_); +#endif // notify all waiting fibers for ( fiber_context * f : waiting) { @@ -57,7 +61,9 @@ bool fiber_context::join( fiber_context * f) { BOOST_ASSERT( nullptr != f); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( is_terminated() ) { return false; } diff --git a/src/fiber_manager.cpp b/src/fiber_manager.cpp index b4a2b7b8..330c4177 100644 --- a/src/fiber_manager.cpp +++ b/src/fiber_manager.cpp @@ -80,7 +80,6 @@ fiber_manager::next_wakeup() { if ( wqueue_.empty() ) { return std::chrono::high_resolution_clock::now() + wait_interval_; } else { - //FIXME: search for the closest time_point to now() in waiting-queue std::chrono::high_resolution_clock::time_point wakeup( wqueue_.top()->time_point() ); if ( (std::chrono::high_resolution_clock::time_point::max)() == wakeup) { return std::chrono::high_resolution_clock::now() + wait_interval_; @@ -129,16 +128,18 @@ fiber_manager::run() { } } +#if defined(BOOST_FIBERS_THREADSAFE) void fiber_manager::wait( std::unique_lock< detail::spinlock > & lk) { wait_until( - std::chrono::high_resolution_clock::time_point( (std::chrono::high_resolution_clock::duration::max)() ), + std::chrono::high_resolution_clock::time_point( + (std::chrono::high_resolution_clock::duration::max)() ), lk); } bool fiber_manager::wait_until( std::chrono::high_resolution_clock::time_point const& timeout_time, - std::unique_lock< detail::spinlock > & lk) { + std::unique_lock< detail::spinlock > & lk) { BOOST_ASSERT( active_fiber_->is_running() ); // set active-fiber to state_waiting @@ -154,6 +155,30 @@ fiber_manager::wait_until( std::chrono::high_resolution_clock::time_point const& return std::chrono::high_resolution_clock::now() < timeout_time; } +#else +void +fiber_manager::wait() { + wait_until( + std::chrono::high_resolution_clock::time_point( + (std::chrono::high_resolution_clock::duration::max)() ) ); +} + +bool +fiber_manager::wait_until( std::chrono::high_resolution_clock::time_point const& timeout_time) { + BOOST_ASSERT( active_fiber_->is_running() ); + + // set active-fiber to state_waiting + active_fiber_->set_waiting(); + // push active-fiber to wqueue_ + active_fiber_->time_point( timeout_time); + wqueue_.push( active_fiber_); + // switch to another fiber + run(); + // fiber is resumed + + return std::chrono::high_resolution_clock::now() < timeout_time; +} +#endif void fiber_manager::yield() { diff --git a/src/mutex.cpp b/src/mutex.cpp index f28c0084..bd1166c0 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -34,7 +34,9 @@ mutex::lock_if_unlocked_() { } mutex::mutex() : +#if defined(BOOST_FIBERS_THREADSAFE) splk_(), +#endif state_( mutex_status::unlocked), owner_(), waiting_() { @@ -50,7 +52,9 @@ mutex::lock() { fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return; @@ -60,20 +64,29 @@ mutex::lock() { BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber detail::scheduler::instance()->wait( lk); +#else + // suspend this fiber + detail::scheduler::instance()->wait(); +#endif } } bool mutex::try_lock() { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return true; } +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif // let other fiber release the lock this_fiber::yield(); return false; @@ -84,7 +97,9 @@ mutex::unlock() { BOOST_ASSERT( mutex_status::locked == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif fiber_context * f( nullptr); if ( ! waiting_.empty() ) { f = waiting_.front(); @@ -93,7 +108,9 @@ mutex::unlock() { } owner_ = fiber_context::id(); state_ = mutex_status::unlocked; +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif if ( nullptr != f) { BOOST_ASSERT( ! f->is_terminated() ); f->set_ready(); diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp index b90503df..a4dad734 100644 --- a/src/recursive_mutex.cpp +++ b/src/recursive_mutex.cpp @@ -38,7 +38,9 @@ recursive_mutex::lock_if_unlocked_() { } recursive_mutex::recursive_mutex() : +#if defined(BOOST_FIBERS_THREADSAFE) splk_(), +#endif state_( mutex_status::unlocked), owner_(), count_( 0), @@ -56,7 +58,9 @@ recursive_mutex::lock() { fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return; @@ -66,20 +70,29 @@ recursive_mutex::lock() { BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber detail::scheduler::instance()->wait( lk); +#else + // suspend this fiber + detail::scheduler::instance()->wait(); +#endif } } bool recursive_mutex::try_lock() { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return true; } +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif // let other fiber release the lock this_fiber::yield(); return false; @@ -90,7 +103,9 @@ recursive_mutex::unlock() { BOOST_ASSERT( mutex_status::locked == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif fiber_context * f( nullptr); if ( 0 == --count_) { if ( ! waiting_.empty() ) { @@ -100,7 +115,9 @@ recursive_mutex::unlock() { } owner_ = fiber_context::id(); state_ = mutex_status::unlocked; +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif if ( nullptr != f) { BOOST_ASSERT( ! f->is_terminated() ); f->set_ready(); diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp index 3b33c7be..4fb44038 100644 --- a/src/recursive_timed_mutex.cpp +++ b/src/recursive_timed_mutex.cpp @@ -38,7 +38,9 @@ recursive_timed_mutex::lock_if_unlocked_() { } recursive_timed_mutex::recursive_timed_mutex() : +#if defined(BOOST_FIBERS_THREADSAFE) splk_(), +#endif state_( mutex_status::unlocked), owner_(), count_( 0), @@ -56,7 +58,9 @@ recursive_timed_mutex::lock() { fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return; @@ -66,20 +70,29 @@ recursive_timed_mutex::lock() { BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber detail::scheduler::instance()->wait( lk); +#else + // suspend this fiber + detail::scheduler::instance()->wait(); +#endif } } bool recursive_timed_mutex::try_lock() { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return true; } +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif // let other fiber release the lock this_fiber::yield(); return false; @@ -90,7 +103,9 @@ recursive_timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_ fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( std::chrono::high_resolution_clock::now() > timeout_time) { return false; @@ -104,6 +119,7 @@ recursive_timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_ BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber until notified or timed-out if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) { lk.lock(); @@ -115,6 +131,17 @@ recursive_timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_ lk.unlock(); return false; } +#else + // suspend this fiber until notified or timed-out + if ( ! detail::scheduler::instance()->wait_until( timeout_time) ) { + std::deque< fiber_context * >::iterator i( std::find( waiting_.begin(), waiting_.end(), f) ); + if ( waiting_.end() != i) { + // remove fiber from waiting-list + waiting_.erase( i); + } + return false; + } +#endif } } @@ -123,7 +150,9 @@ recursive_timed_mutex::unlock() { BOOST_ASSERT( mutex_status::locked == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif fiber_context * f( nullptr); if ( 0 == --count_) { if ( ! waiting_.empty() ) { @@ -133,7 +162,9 @@ recursive_timed_mutex::unlock() { } owner_ = fiber_context::id(); state_ = mutex_status::unlocked; +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif if ( nullptr != f) { BOOST_ASSERT( ! f->is_terminated() ); f->set_ready(); diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp index fa55248c..f5971b1a 100644 --- a/src/timed_mutex.cpp +++ b/src/timed_mutex.cpp @@ -34,7 +34,9 @@ timed_mutex::lock_if_unlocked_() { } timed_mutex::timed_mutex() : +#if defined(BOOST_FIBERS_THREADSAFE) splk_(), +#endif state_( mutex_status::unlocked), owner_(), waiting_() { @@ -50,7 +52,9 @@ timed_mutex::lock() { fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return; @@ -60,20 +64,29 @@ timed_mutex::lock() { BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber detail::scheduler::instance()->wait( lk); +#else + // suspend this fiber + detail::scheduler::instance()->wait(); +#endif } } bool timed_mutex::try_lock() { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( lock_if_unlocked_() ) { return true; } +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif // let other fiber release the lock this_fiber::yield(); return false; @@ -84,7 +97,9 @@ timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_point cons fiber_context * f( detail::scheduler::instance()->active() ); BOOST_ASSERT( nullptr != f); for (;;) { +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif if ( std::chrono::high_resolution_clock::now() > timeout_time) { return false; @@ -98,6 +113,7 @@ timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_point cons BOOST_ASSERT( waiting_.end() == std::find( waiting_.begin(), waiting_.end(), f) ); waiting_.push_back( f); +#if defined(BOOST_FIBERS_THREADSAFE) // suspend this fiber until notified or timed-out if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) { lk.lock(); @@ -109,6 +125,17 @@ timed_mutex::try_lock_until( std::chrono::high_resolution_clock::time_point cons lk.unlock(); return false; } +#else + // suspend this fiber until notified or timed-out + if ( ! detail::scheduler::instance()->wait_until( timeout_time) ) { + std::deque< fiber_context * >::iterator i( std::find( waiting_.begin(), waiting_.end(), f) ); + if ( waiting_.end() != i) { + // remove fiber from waiting-list + waiting_.erase( i); + } + return false; + } +#endif } } @@ -117,7 +144,9 @@ timed_mutex::unlock() { BOOST_ASSERT( mutex_status::locked == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); +#if defined(BOOST_FIBERS_THREADSAFE) std::unique_lock< detail::spinlock > lk( splk_); +#endif fiber_context * f( nullptr); if ( ! waiting_.empty() ) { f = waiting_.front(); @@ -126,7 +155,9 @@ timed_mutex::unlock() { } owner_ = fiber_context::id(); state_ = mutex_status::unlocked; +#if defined(BOOST_FIBERS_THREADSAFE) lk.unlock(); +#endif if ( nullptr != f) { BOOST_ASSERT( ! f->is_terminated() ); f->set_ready(); diff --git a/test/test_condition_mt.cpp b/test/test_condition_mt.cpp index eb1e5146..2a8f4e4f 100644 --- a/test/test_condition_mt.cpp +++ b/test/test_condition_mt.cpp @@ -128,13 +128,19 @@ void test_two_waiter_notify_all() BOOST_CHECK( 2 == value); } +void test_dummy() {} + boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { boost::unit_test::test_suite * test = BOOST_TEST_SUITE("Boost.Fiber: multithreaded condition test suite"); +#if defined(BOOST_FIBERS_THREADSAFE) test->add( BOOST_TEST_CASE( & test_one_waiter_notify_one) ); test->add( BOOST_TEST_CASE( & test_two_waiter_notify_all) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif return test; } diff --git a/test/test_futures_mt.cpp b/test/test_futures_mt.cpp index 8bdbba03..20ca3b46 100644 --- a/test/test_futures_mt.cpp +++ b/test/test_futures_mt.cpp @@ -54,13 +54,19 @@ void test_async() BOOST_CHECK_EQUAL( i, result); } +void test_dummy() {} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Fiber: futures-mt test suite"); +#if defined(BOOST_FIBERS_THREADSAFE) for ( int i = 0; i < 50; ++i) { test->add(BOOST_TEST_CASE(test_async)); } +#else + test->add(BOOST_TEST_CASE(test_dummy)); +#endif return test; } diff --git a/test/test_mutex_mt.cpp b/test/test_mutex_mt.cpp index 9ac9b979..8f549fb5 100644 --- a/test/test_mutex_mt.cpp +++ b/test/test_mutex_mt.cpp @@ -130,15 +130,21 @@ void test_timed_mutex() } } +void test_dummy() {} + boost::unit_test::test_suite * init_unit_test_suite( int, char* []) { boost::unit_test::test_suite * test = BOOST_TEST_SUITE("Boost.Fiber: multithreaded mutex test suite"); +#if defined(BOOST_FIBERS_THREADSAFE) test->add( BOOST_TEST_CASE( & test_mutex) ); test->add( BOOST_TEST_CASE( & test_recursive_mutex) ); test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) ); test->add( BOOST_TEST_CASE( & test_timed_mutex) ); +#else + test->add( BOOST_TEST_CASE( & test_dummy) ); +#endif return test; }