shared_state.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // Copyright Oliver Kowalke 2013.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_FIBERS_DETAIL_SHARED_STATE_H
  6. #define BOOST_FIBERS_DETAIL_SHARED_STATE_H
  7. #include <algorithm>
  8. #include <atomic>
  9. #include <chrono>
  10. #include <cstddef>
  11. #include <exception>
  12. #include <memory>
  13. #include <mutex>
  14. #include <type_traits>
  15. #include <boost/assert.hpp>
  16. #include <boost/config.hpp>
  17. #include <boost/intrusive_ptr.hpp>
  18. #include <boost/fiber/detail/config.hpp>
  19. #include <boost/fiber/future/future_status.hpp>
  20. #include <boost/fiber/condition_variable.hpp>
  21. #include <boost/fiber/exceptions.hpp>
  22. #include <boost/fiber/mutex.hpp>
  23. #ifdef BOOST_HAS_ABI_HEADERS
  24. # include BOOST_ABI_PREFIX
  25. #endif
  26. namespace boost {
  27. namespace fibers {
  28. namespace detail {
  29. class shared_state_base {
  30. private:
  31. std::atomic< std::size_t > use_count_{ 0 };
  32. mutable condition_variable waiters_{};
  33. protected:
  34. mutable mutex mtx_{};
  35. bool ready_{ false };
  36. std::exception_ptr except_{};
  37. void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept {
  38. BOOST_ASSERT( lk.owns_lock() );
  39. ready_ = true;
  40. lk.unlock();
  41. waiters_.notify_all();
  42. }
  43. void owner_destroyed_( std::unique_lock< mutex > & lk) {
  44. BOOST_ASSERT( lk.owns_lock() );
  45. if ( ! ready_) {
  46. set_exception_(
  47. std::make_exception_ptr( broken_promise() ),
  48. lk);
  49. }
  50. }
  51. void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) {
  52. BOOST_ASSERT( lk.owns_lock() );
  53. if ( BOOST_UNLIKELY( ready_) ) {
  54. throw promise_already_satisfied();
  55. }
  56. except_ = except;
  57. mark_ready_and_notify_( lk);
  58. }
  59. std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) {
  60. BOOST_ASSERT( lk.owns_lock() );
  61. wait_( lk);
  62. return except_;
  63. }
  64. void wait_( std::unique_lock< mutex > & lk) const {
  65. BOOST_ASSERT( lk.owns_lock() );
  66. waiters_.wait( lk, [this](){ return ready_; });
  67. }
  68. template< typename Rep, typename Period >
  69. future_status wait_for_( std::unique_lock< mutex > & lk,
  70. std::chrono::duration< Rep, Period > const& timeout_duration) const {
  71. BOOST_ASSERT( lk.owns_lock() );
  72. return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; })
  73. ? future_status::ready
  74. : future_status::timeout;
  75. }
  76. template< typename Clock, typename Duration >
  77. future_status wait_until_( std::unique_lock< mutex > & lk,
  78. std::chrono::time_point< Clock, Duration > const& timeout_time) const {
  79. BOOST_ASSERT( lk.owns_lock() );
  80. return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; })
  81. ? future_status::ready
  82. : future_status::timeout;
  83. }
  84. virtual void deallocate_future() noexcept = 0;
  85. public:
  86. shared_state_base() = default;
  87. virtual ~shared_state_base() = default;
  88. shared_state_base( shared_state_base const&) = delete;
  89. shared_state_base & operator=( shared_state_base const&) = delete;
  90. void owner_destroyed() {
  91. std::unique_lock< mutex > lk{ mtx_ };
  92. owner_destroyed_( lk);
  93. }
  94. void set_exception( std::exception_ptr except) {
  95. std::unique_lock< mutex > lk{ mtx_ };
  96. set_exception_( except, lk);
  97. }
  98. std::exception_ptr get_exception_ptr() {
  99. std::unique_lock< mutex > lk{ mtx_ };
  100. return get_exception_ptr_( lk);
  101. }
  102. void wait() const {
  103. std::unique_lock< mutex > lk{ mtx_ };
  104. wait_( lk);
  105. }
  106. template< typename Rep, typename Period >
  107. future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
  108. std::unique_lock< mutex > lk{ mtx_ };
  109. return wait_for_( lk, timeout_duration);
  110. }
  111. template< typename Clock, typename Duration >
  112. future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
  113. std::unique_lock< mutex > lk{ mtx_ };
  114. return wait_until_( lk, timeout_time);
  115. }
  116. friend inline
  117. void intrusive_ptr_add_ref( shared_state_base * p) noexcept {
  118. p->use_count_.fetch_add( 1, std::memory_order_relaxed);
  119. }
  120. friend inline
  121. void intrusive_ptr_release( shared_state_base * p) noexcept {
  122. if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) {
  123. std::atomic_thread_fence( std::memory_order_acquire);
  124. p->deallocate_future();
  125. }
  126. }
  127. };
  128. template< typename R >
  129. class shared_state : public shared_state_base {
  130. private:
  131. typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_{};
  132. void set_value_( R const& value, std::unique_lock< mutex > & lk) {
  133. BOOST_ASSERT( lk.owns_lock() );
  134. if ( BOOST_UNLIKELY( ready_) ) {
  135. throw promise_already_satisfied{};
  136. }
  137. ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( value );
  138. mark_ready_and_notify_( lk);
  139. }
  140. void set_value_( R && value, std::unique_lock< mutex > & lk) {
  141. BOOST_ASSERT( lk.owns_lock() );
  142. if ( BOOST_UNLIKELY( ready_) ) {
  143. throw promise_already_satisfied{};
  144. }
  145. ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( std::move( value) );
  146. mark_ready_and_notify_( lk);
  147. }
  148. R & get_( std::unique_lock< mutex > & lk) {
  149. BOOST_ASSERT( lk.owns_lock() );
  150. wait_( lk);
  151. if ( except_) {
  152. std::rethrow_exception( except_);
  153. }
  154. return * reinterpret_cast< R * >( std::addressof( storage_) );
  155. }
  156. public:
  157. typedef intrusive_ptr< shared_state > ptr_type;
  158. shared_state() = default;
  159. virtual ~shared_state() {
  160. if ( ready_ && ! except_) {
  161. reinterpret_cast< R * >( std::addressof( storage_) )->~R();
  162. }
  163. }
  164. shared_state( shared_state const&) = delete;
  165. shared_state & operator=( shared_state const&) = delete;
  166. void set_value( R const& value) {
  167. std::unique_lock< mutex > lk{ mtx_ };
  168. set_value_( value, lk);
  169. }
  170. void set_value( R && value) {
  171. std::unique_lock< mutex > lk{ mtx_ };
  172. set_value_( std::move( value), lk);
  173. }
  174. R & get() {
  175. std::unique_lock< mutex > lk{ mtx_ };
  176. return get_( lk);
  177. }
  178. };
  179. template< typename R >
  180. class shared_state< R & > : public shared_state_base {
  181. private:
  182. R * value_{ nullptr };
  183. void set_value_( R & value, std::unique_lock< mutex > & lk) {
  184. BOOST_ASSERT( lk.owns_lock() );
  185. if ( BOOST_UNLIKELY( ready_) ) {
  186. throw promise_already_satisfied();
  187. }
  188. value_ = std::addressof( value);
  189. mark_ready_and_notify_( lk);
  190. }
  191. R & get_( std::unique_lock< mutex > & lk) {
  192. BOOST_ASSERT( lk.owns_lock() );
  193. wait_( lk);
  194. if ( except_) {
  195. std::rethrow_exception( except_);
  196. }
  197. return * value_;
  198. }
  199. public:
  200. typedef intrusive_ptr< shared_state > ptr_type;
  201. shared_state() = default;
  202. virtual ~shared_state() = default;
  203. shared_state( shared_state const&) = delete;
  204. shared_state & operator=( shared_state const&) = delete;
  205. void set_value( R & value) {
  206. std::unique_lock< mutex > lk{ mtx_ };
  207. set_value_( value, lk);
  208. }
  209. R & get() {
  210. std::unique_lock< mutex > lk{ mtx_ };
  211. return get_( lk);
  212. }
  213. };
  214. template<>
  215. class shared_state< void > : public shared_state_base {
  216. private:
  217. inline
  218. void set_value_( std::unique_lock< mutex > & lk) {
  219. BOOST_ASSERT( lk.owns_lock() );
  220. if ( BOOST_UNLIKELY( ready_) ) {
  221. throw promise_already_satisfied();
  222. }
  223. mark_ready_and_notify_( lk);
  224. }
  225. inline
  226. void get_( std::unique_lock< mutex > & lk) {
  227. BOOST_ASSERT( lk.owns_lock() );
  228. wait_( lk);
  229. if ( except_) {
  230. std::rethrow_exception( except_);
  231. }
  232. }
  233. public:
  234. typedef intrusive_ptr< shared_state > ptr_type;
  235. shared_state() = default;
  236. virtual ~shared_state() = default;
  237. shared_state( shared_state const&) = delete;
  238. shared_state & operator=( shared_state const&) = delete;
  239. inline
  240. void set_value() {
  241. std::unique_lock< mutex > lk{ mtx_ };
  242. set_value_( lk);
  243. }
  244. inline
  245. void get() {
  246. std::unique_lock< mutex > lk{ mtx_ };
  247. get_( lk);
  248. }
  249. };
  250. }}}
  251. #ifdef BOOST_HAS_ABI_HEADERS
  252. # include BOOST_ABI_SUFFIX
  253. #endif
  254. #endif // BOOST_FIBERS_DETAIL_SHARED_STATE_H