123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- // Copyright Oliver Kowalke 2013.
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_FIBERS_DETAIL_SHARED_STATE_H
- #define BOOST_FIBERS_DETAIL_SHARED_STATE_H
- #include <algorithm>
- #include <atomic>
- #include <chrono>
- #include <cstddef>
- #include <exception>
- #include <memory>
- #include <mutex>
- #include <type_traits>
- #include <boost/assert.hpp>
- #include <boost/config.hpp>
- #include <boost/intrusive_ptr.hpp>
- #include <boost/fiber/detail/config.hpp>
- #include <boost/fiber/future/future_status.hpp>
- #include <boost/fiber/condition_variable.hpp>
- #include <boost/fiber/exceptions.hpp>
- #include <boost/fiber/mutex.hpp>
- #ifdef BOOST_HAS_ABI_HEADERS
- # include BOOST_ABI_PREFIX
- #endif
- namespace boost {
- namespace fibers {
- namespace detail {
- class shared_state_base {
- private:
- std::atomic< std::size_t > use_count_{ 0 };
- mutable condition_variable waiters_{};
- protected:
- mutable mutex mtx_{};
- bool ready_{ false };
- std::exception_ptr except_{};
- void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept {
- BOOST_ASSERT( lk.owns_lock() );
- ready_ = true;
- lk.unlock();
- waiters_.notify_all();
- }
- void owner_destroyed_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( ! ready_) {
- set_exception_(
- std::make_exception_ptr( broken_promise() ),
- lk);
- }
- }
- void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( BOOST_UNLIKELY( ready_) ) {
- throw promise_already_satisfied();
- }
- except_ = except;
- mark_ready_and_notify_( lk);
- }
- std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- wait_( lk);
- return except_;
- }
- void wait_( std::unique_lock< mutex > & lk) const {
- BOOST_ASSERT( lk.owns_lock() );
- waiters_.wait( lk, [this](){ return ready_; });
- }
- template< typename Rep, typename Period >
- future_status wait_for_( std::unique_lock< mutex > & lk,
- std::chrono::duration< Rep, Period > const& timeout_duration) const {
- BOOST_ASSERT( lk.owns_lock() );
- return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; })
- ? future_status::ready
- : future_status::timeout;
- }
- template< typename Clock, typename Duration >
- future_status wait_until_( std::unique_lock< mutex > & lk,
- std::chrono::time_point< Clock, Duration > const& timeout_time) const {
- BOOST_ASSERT( lk.owns_lock() );
- return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; })
- ? future_status::ready
- : future_status::timeout;
- }
- virtual void deallocate_future() noexcept = 0;
- public:
- shared_state_base() = default;
- virtual ~shared_state_base() = default;
- shared_state_base( shared_state_base const&) = delete;
- shared_state_base & operator=( shared_state_base const&) = delete;
- void owner_destroyed() {
- std::unique_lock< mutex > lk{ mtx_ };
- owner_destroyed_( lk);
- }
- void set_exception( std::exception_ptr except) {
- std::unique_lock< mutex > lk{ mtx_ };
- set_exception_( except, lk);
- }
- std::exception_ptr get_exception_ptr() {
- std::unique_lock< mutex > lk{ mtx_ };
- return get_exception_ptr_( lk);
- }
- void wait() const {
- std::unique_lock< mutex > lk{ mtx_ };
- wait_( lk);
- }
- template< typename Rep, typename Period >
- future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
- std::unique_lock< mutex > lk{ mtx_ };
- return wait_for_( lk, timeout_duration);
- }
- template< typename Clock, typename Duration >
- future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
- std::unique_lock< mutex > lk{ mtx_ };
- return wait_until_( lk, timeout_time);
- }
- friend inline
- void intrusive_ptr_add_ref( shared_state_base * p) noexcept {
- p->use_count_.fetch_add( 1, std::memory_order_relaxed);
- }
- friend inline
- void intrusive_ptr_release( shared_state_base * p) noexcept {
- if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) {
- std::atomic_thread_fence( std::memory_order_acquire);
- p->deallocate_future();
- }
- }
- };
- template< typename R >
- class shared_state : public shared_state_base {
- private:
- typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_{};
- void set_value_( R const& value, std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( BOOST_UNLIKELY( ready_) ) {
- throw promise_already_satisfied{};
- }
- ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( value );
- mark_ready_and_notify_( lk);
- }
- void set_value_( R && value, std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( BOOST_UNLIKELY( ready_) ) {
- throw promise_already_satisfied{};
- }
- ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( std::move( value) );
- mark_ready_and_notify_( lk);
- }
- R & get_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- wait_( lk);
- if ( except_) {
- std::rethrow_exception( except_);
- }
- return * reinterpret_cast< R * >( std::addressof( storage_) );
- }
- public:
- typedef intrusive_ptr< shared_state > ptr_type;
- shared_state() = default;
- virtual ~shared_state() {
- if ( ready_ && ! except_) {
- reinterpret_cast< R * >( std::addressof( storage_) )->~R();
- }
- }
- shared_state( shared_state const&) = delete;
- shared_state & operator=( shared_state const&) = delete;
- void set_value( R const& value) {
- std::unique_lock< mutex > lk{ mtx_ };
- set_value_( value, lk);
- }
- void set_value( R && value) {
- std::unique_lock< mutex > lk{ mtx_ };
- set_value_( std::move( value), lk);
- }
- R & get() {
- std::unique_lock< mutex > lk{ mtx_ };
- return get_( lk);
- }
- };
- template< typename R >
- class shared_state< R & > : public shared_state_base {
- private:
- R * value_{ nullptr };
- void set_value_( R & value, std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( BOOST_UNLIKELY( ready_) ) {
- throw promise_already_satisfied();
- }
- value_ = std::addressof( value);
- mark_ready_and_notify_( lk);
- }
- R & get_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- wait_( lk);
- if ( except_) {
- std::rethrow_exception( except_);
- }
- return * value_;
- }
- public:
- typedef intrusive_ptr< shared_state > ptr_type;
- shared_state() = default;
- virtual ~shared_state() = default;
- shared_state( shared_state const&) = delete;
- shared_state & operator=( shared_state const&) = delete;
- void set_value( R & value) {
- std::unique_lock< mutex > lk{ mtx_ };
- set_value_( value, lk);
- }
- R & get() {
- std::unique_lock< mutex > lk{ mtx_ };
- return get_( lk);
- }
- };
- template<>
- class shared_state< void > : public shared_state_base {
- private:
- inline
- void set_value_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- if ( BOOST_UNLIKELY( ready_) ) {
- throw promise_already_satisfied();
- }
- mark_ready_and_notify_( lk);
- }
- inline
- void get_( std::unique_lock< mutex > & lk) {
- BOOST_ASSERT( lk.owns_lock() );
- wait_( lk);
- if ( except_) {
- std::rethrow_exception( except_);
- }
- }
- public:
- typedef intrusive_ptr< shared_state > ptr_type;
- shared_state() = default;
- virtual ~shared_state() = default;
- shared_state( shared_state const&) = delete;
- shared_state & operator=( shared_state const&) = delete;
- inline
- void set_value() {
- std::unique_lock< mutex > lk{ mtx_ };
- set_value_( lk);
- }
- inline
- void get() {
- std::unique_lock< mutex > lk{ mtx_ };
- get_( lk);
- }
- };
- }}}
- #ifdef BOOST_HAS_ABI_HEADERS
- # include BOOST_ABI_SUFFIX
- #endif
- #endif // BOOST_FIBERS_DETAIL_SHARED_STATE_H
|