From 1c8cd1d880b9129e47ba8885be0afdbff1a45d63 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Tue, 5 Nov 2013 16:13:29 +0100 Subject: [PATCH] protect mutex' with spunlock only --- include/boost/fiber/algorithm.hpp | 2 + include/boost/fiber/detail/fiber_base.hpp | 55 +------ include/boost/fiber/detail/main_notifier.hpp | 20 +-- include/boost/fiber/detail/notify.hpp | 52 +++++++ include/boost/fiber/detail/scheduler.hpp | 8 +- include/boost/fiber/mutex.hpp | 5 +- include/boost/fiber/operations.hpp | 2 +- include/boost/fiber/recursive_mutex.hpp | 7 +- include/boost/fiber/recursive_timed_mutex.hpp | 7 +- include/boost/fiber/round_robin.hpp | 5 + include/boost/fiber/round_robin_ws.hpp | 5 + include/boost/fiber/timed_mutex.hpp | 5 +- src/detail/scheduler.cpp | 7 + src/mutex.cpp | 59 ++++--- src/recursive_mutex.cpp | 89 ++++++----- src/recursive_timed_mutex.cpp | 146 ++++++++++-------- src/round_robin.cpp | 3 +- src/round_robin_ws.cpp | 3 +- src/timed_mutex.cpp | 95 +++++++----- 19 files changed, 323 insertions(+), 252 deletions(-) diff --git a/include/boost/fiber/algorithm.hpp b/include/boost/fiber/algorithm.hpp index 9436e898..5f47a1d8 100644 --- a/include/boost/fiber/algorithm.hpp +++ b/include/boost/fiber/algorithm.hpp @@ -50,6 +50,8 @@ struct algorithm : private noncopyable virtual void yield() = 0; + virtual detail::fiber_base::id get_main_id() = 0; + virtual ~algorithm() {} }; diff --git a/include/boost/fiber/detail/fiber_base.hpp b/include/boost/fiber/detail/fiber_base.hpp index 9f465252..b5ed2dd3 100644 --- a/include/boost/fiber/detail/fiber_base.hpp +++ b/include/boost/fiber/detail/fiber_base.hpp @@ -8,7 +8,6 @@ #define BOOST_FIBERS_DETAIL_FIBER_BASE_H #include -#include #include #include @@ -102,58 +101,6 @@ protected: virtual void run() = 0; public: - class id - { - private: - friend class fiber_base; - - fiber_base const* impl_; - - public: - explicit id( fiber_base const* impl) BOOST_NOEXCEPT : - impl_( impl) - {} - - public: - id() BOOST_NOEXCEPT : - impl_() - {} - - bool operator==( id const& other) const BOOST_NOEXCEPT - { return impl_ == other.impl_; } - - bool operator!=( id const& other) const BOOST_NOEXCEPT - { return impl_ != other.impl_; } - - bool operator<( id const& other) const BOOST_NOEXCEPT - { return impl_ < other.impl_; } - - bool operator>( id const& other) const BOOST_NOEXCEPT - { return other.impl_ < impl_; } - - bool operator<=( id const& other) const BOOST_NOEXCEPT - { return ! ( * this > other); } - - bool operator>=( id const& other) const BOOST_NOEXCEPT - { return ! ( * this < other); } - - template< typename charT, class traitsT > - friend std::basic_ostream< charT, traitsT > & - operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) - { - if ( 0 != other.impl_) - return os << other.impl_; - else - return os << "{not-valid}"; - } - - operator bool() const BOOST_NOEXCEPT - { return 0 != impl_; } - - bool operator!() const BOOST_NOEXCEPT - { return 0 == impl_; } - }; - template< typename StackAllocator, typename Allocator > fiber_base( attributes const& attrs, StackAllocator const& stack_alloc, Allocator const& alloc) : fss_data_(), @@ -187,7 +134,7 @@ public: virtual ~fiber_base(); id get_id() const BOOST_NOEXCEPT - { return id( this); } + { return id( const_cast< fiber_base * >( this) ); } int priority() const BOOST_NOEXCEPT { return priority_; } diff --git a/include/boost/fiber/detail/main_notifier.hpp b/include/boost/fiber/detail/main_notifier.hpp index dfc367a3..1be7d328 100644 --- a/include/boost/fiber/detail/main_notifier.hpp +++ b/include/boost/fiber/detail/main_notifier.hpp @@ -6,6 +6,7 @@ #ifndef BOOST_FIBERS_DETAIL_MAIN_NOTIFIER_H #define BOOST_FIBERS_DETAIL_MAIN_NOTIFIER_H +#include #include #include @@ -19,7 +20,7 @@ namespace boost { namespace fibers { namespace detail { -class main_notifier : public detail::notify +class main_notifier : public notify { public: static ptr_t make_pointer( main_notifier & n) { @@ -33,14 +34,7 @@ public: {} bool is_ready() const BOOST_NOEXCEPT - { - if ( ready_) - { - ready_ = false; - return true; - } - return false; - } + { return ready_; } void set_ready() BOOST_NOEXCEPT { ready_ = true; } @@ -48,8 +42,14 @@ public: void deallocate_object() {} + id get_id() const BOOST_NOEXCEPT + { return id( const_cast< main_notifier * >( this) ); } + private: - mutable bool ready_; + atomic< bool > ready_; + + main_notifier( main_notifier const&); + main_notifier & operator=( main_notifier const&); }; }}} diff --git a/include/boost/fiber/detail/notify.hpp b/include/boost/fiber/detail/notify.hpp index 90122b6d..5f45e1d0 100644 --- a/include/boost/fiber/detail/notify.hpp +++ b/include/boost/fiber/detail/notify.hpp @@ -8,6 +8,7 @@ #define BOOST_FIBERS_DETAIL_NOTIFY_H #include +#include #include #include @@ -41,6 +42,55 @@ protected: public: typedef intrusive_ptr< notify > ptr_t; + class id + { + private: + notify::ptr_t impl_; + + public: + id() BOOST_NOEXCEPT : + impl_() + {} + + explicit id( notify::ptr_t impl) BOOST_NOEXCEPT : + impl_( impl) + {} + + bool operator==( id const& other) const BOOST_NOEXCEPT + { return impl_ == other.impl_; } + + bool operator!=( id const& other) const BOOST_NOEXCEPT + { return impl_ != other.impl_; } + + bool operator<( id const& other) const BOOST_NOEXCEPT + { return impl_ < other.impl_; } + + bool operator>( id const& other) const BOOST_NOEXCEPT + { return other.impl_ < impl_; } + + bool operator<=( id const& other) const BOOST_NOEXCEPT + { return ! ( * this > other); } + + bool operator>=( id const& other) const BOOST_NOEXCEPT + { return ! ( * this < other); } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) + { + if ( 0 != other.impl_) + return os << other.impl_; + else + return os << "{not-valid}"; + } + + operator bool() const BOOST_NOEXCEPT + { return 0 != impl_; } + + bool operator!() const BOOST_NOEXCEPT + { return 0 == impl_; } + }; + notify() : use_count_( 0) {} @@ -51,6 +101,8 @@ public: virtual void set_ready() BOOST_NOEXCEPT = 0; + virtual id get_id() const BOOST_NOEXCEPT = 0; + friend inline void intrusive_ptr_add_ref( notify * p) BOOST_NOEXCEPT { ++p->use_count_; } diff --git a/include/boost/fiber/detail/scheduler.hpp b/include/boost/fiber/detail/scheduler.hpp index 187d0291..770d78cd 100644 --- a/include/boost/fiber/detail/scheduler.hpp +++ b/include/boost/fiber/detail/scheduler.hpp @@ -12,6 +12,8 @@ #include #include +#include +#include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -29,9 +31,13 @@ namespace detail { class scheduler : private noncopyable { private: - static thread_specific_ptr< algorithm > instance_; + static thread_specific_ptr< algorithm > instance_; public: + typedef main_notifier local_context; + + static notify::ptr_t make_notification( main_notifier &); + template< typename F > static fiber_base::ptr_t extract( F const& f) { return f.impl_; } diff --git a/include/boost/fiber/mutex.hpp b/include/boost/fiber/mutex.hpp index 7ced9d6c..aba79d13 100644 --- a/include/boost/fiber/mutex.hpp +++ b/include/boost/fiber/mutex.hpp @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -40,9 +39,9 @@ private: UNLOCKED }; - detail::fiber_base::id owner_; - atomic< state_t > state_; detail::spinlock splk_; + state_t state_; + detail::fiber_base::id owner_; std::deque< detail::notify::ptr_t > waiting_; diff --git a/include/boost/fiber/operations.hpp b/include/boost/fiber/operations.hpp index 097c68e9..ea161b1b 100644 --- a/include/boost/fiber/operations.hpp +++ b/include/boost/fiber/operations.hpp @@ -27,7 +27,7 @@ fibers::fiber::id get_id() BOOST_NOEXCEPT { return fibers::detail::scheduler::instance()->active() ? fibers::detail::scheduler::instance()->active()->get_id() - : fibers::fiber::id(); + : fibers::fiber::id( fibers::detail::scheduler::instance()->get_main_id() ); } inline diff --git a/include/boost/fiber/recursive_mutex.hpp b/include/boost/fiber/recursive_mutex.hpp index 711722ab..fe1b0844 100644 --- a/include/boost/fiber/recursive_mutex.hpp +++ b/include/boost/fiber/recursive_mutex.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -43,10 +42,10 @@ private: UNLOCKED }; - detail::fiber_base::id owner_; - atomic< std::size_t > count_; - atomic< state_t > state_; detail::spinlock splk_; + state_t state_; + detail::fiber_base::id owner_; + std::size_t count_; std::deque< detail::notify::ptr_t > waiting_; diff --git a/include/boost/fiber/recursive_timed_mutex.hpp b/include/boost/fiber/recursive_timed_mutex.hpp index 05235f5c..e5c86a65 100644 --- a/include/boost/fiber/recursive_timed_mutex.hpp +++ b/include/boost/fiber/recursive_timed_mutex.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -43,10 +42,10 @@ private: UNLOCKED }; - detail::fiber_base::id owner_; - atomic< std::size_t > count_; - atomic< state_t > state_; detail::spinlock splk_; + state_t state_; + detail::fiber_base::id owner_; + std::size_t count_; std::deque< detail::notify::ptr_t > waiting_; diff --git a/include/boost/fiber/round_robin.hpp b/include/boost/fiber/round_robin.hpp index cf82e3cd..4ff67a09 100644 --- a/include/boost/fiber/round_robin.hpp +++ b/include/boost/fiber/round_robin.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ private: detail::fiber_base::ptr_t active_fiber_; wqueue_t wqueue_; rqueue_t rqueue_; + detail::main_notifier mn_; public: round_robin() BOOST_NOEXCEPT; @@ -77,6 +79,9 @@ public: unique_lock< detail::spinlock > &); void yield(); + + detail::fiber_base::id get_main_id() + { return detail::fiber_base::id( detail::main_notifier::make_pointer( mn_) ); } }; }} diff --git a/include/boost/fiber/round_robin_ws.hpp b/include/boost/fiber/round_robin_ws.hpp index 231ea76a..e5762c4c 100644 --- a/include/boost/fiber/round_robin_ws.hpp +++ b/include/boost/fiber/round_robin_ws.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ private: detail::fiber_base::ptr_t active_fiber_; wqueue_t wqueue_; detail::ws_queue rqueue_; + detail::main_notifier mn_; public: round_robin_ws() BOOST_NOEXCEPT; @@ -78,6 +80,9 @@ public: void yield(); + detail::fiber_base::id get_main_id() + { return detail::fiber_base::id( detail::main_notifier::make_pointer( mn_) ); } + fiber steal_from(); void migrate_to( fiber const&); }; diff --git a/include/boost/fiber/timed_mutex.hpp b/include/boost/fiber/timed_mutex.hpp index 82642bd0..3c0c101e 100644 --- a/include/boost/fiber/timed_mutex.hpp +++ b/include/boost/fiber/timed_mutex.hpp @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -40,9 +39,9 @@ private: UNLOCKED }; - detail::fiber_base::id owner_; - atomic< state_t > state_; detail::spinlock splk_; + state_t state_; + detail::fiber_base::id owner_; std::deque< detail::notify::ptr_t > waiting_; diff --git a/src/detail/scheduler.cpp b/src/detail/scheduler.cpp index be0e33b9..ba76793f 100644 --- a/src/detail/scheduler.cpp +++ b/src/detail/scheduler.cpp @@ -19,6 +19,13 @@ static void cleanup_function( algorithm *) {} thread_specific_ptr< algorithm > scheduler::instance_( cleanup_function); +notify::ptr_t +scheduler::make_notification( main_notifier & n) { + notify::ptr_t p( & n); + intrusive_ptr_add_ref( p.get() ); + return p; +} + algorithm * scheduler::replace( algorithm * other) BOOST_NOEXCEPT { diff --git a/src/mutex.cpp b/src/mutex.cpp index 374742d9..c44abe4b 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -10,7 +10,6 @@ #include -#include "boost/fiber/detail/main_notifier.hpp" #include "boost/fiber/detail/scheduler.hpp" #include "boost/fiber/interruption.hpp" #include "boost/fiber/operations.hpp" @@ -23,9 +22,9 @@ namespace boost { namespace fibers { mutex::mutex() : - owner_(), - state_( UNLOCKED), splk_(), + state_( UNLOCKED), + owner_(), waiting_() {} @@ -45,9 +44,13 @@ mutex::lock() { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -58,17 +61,21 @@ mutex::lock() } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -82,25 +89,27 @@ mutex::lock() } } } - - BOOST_ASSERT( ! owner_); - - owner_ = this_fiber::get_id(); } bool mutex::try_lock() { - state_t expected = UNLOCKED; - if ( ! state_.compare_exchange_strong( expected, LOCKED) ) { + unique_lock< detail::spinlock > lk( splk_); + + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return true; + } + else + { + lk.unlock(); // let other fiber release the lock detail::scheduler::instance()->yield(); return false; } - - owner_ = this_fiber::get_id(); - - return true; } void @@ -111,14 +120,14 @@ mutex::unlock() detail::notify::ptr_t n; unique_lock< detail::spinlock > lk( splk_); - if ( ! waiting_.empty() ) { + if ( ! waiting_.empty() ) + { n.swap( waiting_.front() ); waiting_.pop_front(); } - owner_ = detail::fiber_base::id(); state_ = UNLOCKED; - + lk.unlock(); if ( n) n->set_ready(); } diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp index c8a8cd69..3b80b583 100644 --- a/src/recursive_mutex.cpp +++ b/src/recursive_mutex.cpp @@ -10,7 +10,6 @@ #include -#include "boost/fiber/detail/main_notifier.hpp" #include "boost/fiber/detail/scheduler.hpp" #include "boost/fiber/interruption.hpp" #include "boost/fiber/operations.hpp" @@ -23,10 +22,10 @@ namespace boost { namespace fibers { recursive_mutex::recursive_mutex() : + splk_(), + state_( UNLOCKED), owner_(), count_( 0), - state_( UNLOCKED), - splk_(), waiting_() {} @@ -40,12 +39,6 @@ recursive_mutex::~recursive_mutex() void recursive_mutex::lock() { - if ( LOCKED == state_ && this_fiber::get_id() == owner_) - { - ++count_; - return; - } - detail::notify::ptr_t n( detail::scheduler::instance()->active() ); if ( n) { @@ -53,9 +46,19 @@ recursive_mutex::lock() { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -66,17 +69,27 @@ recursive_mutex::lock() } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -90,35 +103,33 @@ recursive_mutex::lock() } } } - - BOOST_ASSERT( ! owner_); - BOOST_ASSERT( 0 == count_); - - owner_ = this_fiber::get_id(); - ++count_; } bool recursive_mutex::try_lock() { - if ( LOCKED == state_ && this_fiber::get_id() == owner_) + unique_lock< detail::spinlock > lk( splk_); + + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return true; + } + else if ( this_fiber::get_id() == owner_) { ++count_; return true; } - - state_t expected = UNLOCKED; - if ( ! state_.compare_exchange_strong( expected, LOCKED) ) + else { + lk.unlock(); // let other fiber release the lock detail::scheduler::instance()->yield(); return false; } - - owner_ = this_fiber::get_id(); - ++count_; - - return true; } void @@ -126,20 +137,20 @@ recursive_mutex::unlock() { BOOST_ASSERT( LOCKED == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); + + detail::notify::ptr_t n; + unique_lock< detail::spinlock > lk( splk_); if ( 0 == --count_) { - detail::notify::ptr_t n; - - unique_lock< detail::spinlock > lk( splk_); - if ( ! waiting_.empty() ) { + if ( ! waiting_.empty() ) + { n.swap( waiting_.front() ); waiting_.pop_front(); } - owner_ = detail::fiber_base::id(); state_ = UNLOCKED; - + lk.unlock(); if ( n) n->set_ready(); } } diff --git a/src/recursive_timed_mutex.cpp b/src/recursive_timed_mutex.cpp index c20f6ede..c1bd34b5 100644 --- a/src/recursive_timed_mutex.cpp +++ b/src/recursive_timed_mutex.cpp @@ -10,7 +10,6 @@ #include -#include "boost/fiber/detail/main_notifier.hpp" #include "boost/fiber/detail/scheduler.hpp" #include "boost/fiber/interruption.hpp" #include "boost/fiber/operations.hpp" @@ -23,10 +22,10 @@ namespace boost { namespace fibers { recursive_timed_mutex::recursive_timed_mutex() : + splk_(), + state_( UNLOCKED), owner_(), count_( 0), - state_( UNLOCKED), - splk_(), waiting_() {} @@ -40,12 +39,6 @@ recursive_timed_mutex::~recursive_timed_mutex() void recursive_timed_mutex::lock() { - if ( LOCKED == state_ && this_fiber::get_id() == owner_) - { - ++count_; - return; - } - detail::notify::ptr_t n( detail::scheduler::instance()->active() ); if ( n) { @@ -53,9 +46,19 @@ recursive_timed_mutex::lock() { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -66,17 +69,27 @@ recursive_timed_mutex::lock() } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -90,46 +103,38 @@ recursive_timed_mutex::lock() } } } - - BOOST_ASSERT( ! owner_); - BOOST_ASSERT( 0 == count_); - - owner_ = this_fiber::get_id(); - ++count_; } bool recursive_timed_mutex::try_lock() { - if ( LOCKED == state_ && this_fiber::get_id() == owner_) + unique_lock< detail::spinlock > lk( splk_); + + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return true; + } + else if ( this_fiber::get_id() == owner_) { ++count_; return true; } - - state_t expected = UNLOCKED; - if ( ! state_.compare_exchange_strong( expected, LOCKED) ) + else { + lk.unlock(); // let other fiber release the lock detail::scheduler::instance()->yield(); return false; } - - owner_ = this_fiber::get_id(); - ++count_; - - return true; } bool recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_time) { - if ( LOCKED == state_ && this_fiber::get_id() == owner_) - { - ++count_; - return true; - } - detail::notify::ptr_t n( detail::scheduler::instance()->active() ); if ( n) { @@ -140,15 +145,26 @@ recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_tim if ( clock_type::now() > timeout_time) return false; - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; - + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return true; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return true; + } + // store this fiber in order to be notified later waiting_.push_back( n); // suspend this fiber until notified or timed-out - if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) { + if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) + { lk.lock(); // remove fiber from waiting-list waiting_.erase( @@ -160,9 +176,9 @@ recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_tim } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { @@ -171,9 +187,19 @@ recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_tim if ( clock_type::now() > timeout_time) return false; - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + ++count_; + return true; + } + else if ( this_fiber::get_id() == owner_) + { + ++count_; + return true; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -196,14 +222,6 @@ recursive_timed_mutex::try_lock_until( clock_type::time_point const& timeout_tim } } } - - BOOST_ASSERT( ! owner_); - BOOST_ASSERT( 0 == count_); - - owner_ = this_fiber::get_id(); - ++count_; - - return true; } void @@ -211,20 +229,20 @@ recursive_timed_mutex::unlock() { BOOST_ASSERT( LOCKED == state_); BOOST_ASSERT( this_fiber::get_id() == owner_); + + detail::notify::ptr_t n; + unique_lock< detail::spinlock > lk( splk_); if ( 0 == --count_) { - detail::notify::ptr_t n; - - unique_lock< detail::spinlock > lk( splk_); - if ( ! waiting_.empty() ) { + if ( ! waiting_.empty() ) + { n.swap( waiting_.front() ); waiting_.pop_front(); } - owner_ = detail::fiber_base::id(); state_ = UNLOCKED; - + lk.unlock(); if ( n) n->set_ready(); } } diff --git a/src/round_robin.cpp b/src/round_robin.cpp index 8060e79b..84578450 100644 --- a/src/round_robin.cpp +++ b/src/round_robin.cpp @@ -31,7 +31,8 @@ namespace fibers { round_robin::round_robin() BOOST_NOEXCEPT : active_fiber_(), wqueue_(), - rqueue_() + rqueue_(), + mn_() {} round_robin::~round_robin() BOOST_NOEXCEPT diff --git a/src/round_robin_ws.cpp b/src/round_robin_ws.cpp index ec78c2a8..80048708 100644 --- a/src/round_robin_ws.cpp +++ b/src/round_robin_ws.cpp @@ -31,7 +31,8 @@ namespace fibers { round_robin_ws::round_robin_ws() BOOST_NOEXCEPT : active_fiber_(), wqueue_(), - rqueue_() + rqueue_(), + mn_() {} round_robin_ws::~round_robin_ws() BOOST_NOEXCEPT diff --git a/src/timed_mutex.cpp b/src/timed_mutex.cpp index b0aa326c..ff17e6aa 100644 --- a/src/timed_mutex.cpp +++ b/src/timed_mutex.cpp @@ -10,7 +10,6 @@ #include -#include "boost/fiber/detail/main_notifier.hpp" #include "boost/fiber/detail/scheduler.hpp" #include "boost/fiber/interruption.hpp" #include "boost/fiber/operations.hpp" @@ -23,9 +22,9 @@ namespace boost { namespace fibers { timed_mutex::timed_mutex() : - owner_(), - state_( UNLOCKED), splk_(), + state_( UNLOCKED), + owner_(), waiting_() {} @@ -45,9 +44,13 @@ timed_mutex::lock() { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -58,17 +61,21 @@ timed_mutex::lock() } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { unique_lock< detail::spinlock > lk( splk_); - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -82,25 +89,27 @@ timed_mutex::lock() } } } - - BOOST_ASSERT( ! owner_); - - owner_ = this_fiber::get_id(); } bool timed_mutex::try_lock() { - state_t expected = UNLOCKED; - if ( ! state_.compare_exchange_strong( expected, LOCKED) ) { + unique_lock< detail::spinlock > lk( splk_); + + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return true; + } + else + { + lk.unlock(); // let other fiber release the lock detail::scheduler::instance()->yield(); return false; } - - owner_ = this_fiber::get_id(); - - return true; } bool @@ -116,15 +125,20 @@ timed_mutex::try_lock_until( clock_type::time_point const& timeout_time) if ( clock_type::now() > timeout_time) return false; - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return true; + } // store this fiber in order to be notified later waiting_.push_back( n); // suspend this fiber until notified or timed-out - if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) { + if ( ! detail::scheduler::instance()->wait_until( timeout_time, lk) ) + { lk.lock(); // remove fiber from waiting-list waiting_.erase( @@ -136,9 +150,9 @@ timed_mutex::try_lock_until( clock_type::time_point const& timeout_time) } else { - // notifier for main-fiber - detail::main_notifier mn; - n = detail::main_notifier::make_pointer( mn); + // local notification for main-fiber + detail::scheduler::local_context ctx; + n = detail::scheduler::make_notification( ctx); for (;;) { @@ -147,9 +161,13 @@ timed_mutex::try_lock_until( clock_type::time_point const& timeout_time) if ( clock_type::now() > timeout_time) return false; - state_t expected = UNLOCKED; - if ( state_.compare_exchange_strong( expected, LOCKED) ) - break; + if ( UNLOCKED == state_) + { + state_ = LOCKED; + BOOST_ASSERT( ! owner_); + owner_ = this_fiber::get_id(); + return true; + } // store this fiber in order to be notified later waiting_.push_back( n); @@ -172,12 +190,6 @@ timed_mutex::try_lock_until( clock_type::time_point const& timeout_time) } } } - - BOOST_ASSERT( ! owner_); - - owner_ = this_fiber::get_id(); - - return true; } void @@ -187,17 +199,16 @@ timed_mutex::unlock() BOOST_ASSERT( this_fiber::get_id() == owner_); detail::notify::ptr_t n; - unique_lock< detail::spinlock > lk( splk_); + if ( ! waiting_.empty() ) { n.swap( waiting_.front() ); waiting_.pop_front(); } - owner_ = detail::fiber_base::id(); - state_ = UNLOCKED; - + state_ = UNLOCKED; + lk.unlock(); if ( n) n->set_ready(); }