]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/fiber/condition_variable.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / fiber / condition_variable.hpp
1
2 // Copyright Oliver Kowalke 2013.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_FIBERS_CONDITION_VARIABLE_H
8 #define BOOST_FIBERS_CONDITION_VARIABLE_H
9
10 #include <algorithm>
11 #include <atomic>
12 #include <chrono>
13 #include <functional>
14 #include <mutex>
15
16 #include <boost/assert.hpp>
17 #include <boost/config.hpp>
18 #include <boost/context/detail/config.hpp>
19
20 #include <boost/fiber/context.hpp>
21 #include <boost/fiber/detail/config.hpp>
22 #include <boost/fiber/detail/convert.hpp>
23 #include <boost/fiber/detail/spinlock.hpp>
24 #include <boost/fiber/exceptions.hpp>
25 #include <boost/fiber/mutex.hpp>
26 #include <boost/fiber/operations.hpp>
27
28 #ifdef BOOST_HAS_ABI_HEADERS
29 # include BOOST_ABI_PREFIX
30 #endif
31
32 #ifdef _MSC_VER
33 # pragma warning(push)
34 //# pragma warning(disable:4251)
35 #endif
36
37 namespace boost {
38 namespace fibers {
39
40 enum class cv_status {
41 no_timeout = 1,
42 timeout
43 };
44
45 class BOOST_FIBERS_DECL condition_variable_any {
46 private:
47 typedef context::wait_queue_t wait_queue_t;
48
49 detail::spinlock wait_queue_splk_{};
50 wait_queue_t wait_queue_{};
51
52 public:
53 condition_variable_any() = default;
54
55 ~condition_variable_any() {
56 BOOST_ASSERT( wait_queue_.empty() );
57 }
58
59 condition_variable_any( condition_variable_any const&) = delete;
60 condition_variable_any & operator=( condition_variable_any const&) = delete;
61
62 void notify_one() noexcept;
63
64 void notify_all() noexcept;
65
66 template< typename LockType >
67 void wait( LockType & lt) {
68 context * active_ctx = context::active();
69 // atomically call lt.unlock() and block on *this
70 // store this fiber in waiting-queue
71 detail::spinlock_lock lk{ wait_queue_splk_ };
72 BOOST_ASSERT( ! active_ctx->wait_is_linked() );
73 active_ctx->wait_link( wait_queue_);
74 active_ctx->twstatus.store( static_cast< std::intptr_t >( 0), std::memory_order_release);
75 // unlock external lt
76 lt.unlock();
77 // suspend this fiber
78 active_ctx->suspend( lk);
79 // relock external again before returning
80 try {
81 lt.lock();
82 #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
83 } catch ( abi::__forced_unwind const&) {
84 throw;
85 #endif
86 } catch (...) {
87 std::terminate();
88 }
89 // post-conditions
90 BOOST_ASSERT( ! active_ctx->wait_is_linked() );
91 }
92
93 template< typename LockType, typename Pred >
94 void wait( LockType & lt, Pred pred) {
95 while ( ! pred() ) {
96 wait( lt);
97 }
98 }
99
100 template< typename LockType, typename Clock, typename Duration >
101 cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) {
102 context * active_ctx = context::active();
103 cv_status status = cv_status::no_timeout;
104 std::chrono::steady_clock::time_point timeout_time = detail::convert( timeout_time_);
105 // atomically call lt.unlock() and block on *this
106 // store this fiber in waiting-queue
107 detail::spinlock_lock lk{ wait_queue_splk_ };
108 BOOST_ASSERT( ! active_ctx->wait_is_linked() );
109 active_ctx->wait_link( wait_queue_);
110 active_ctx->twstatus.store( reinterpret_cast< std::intptr_t >( this), std::memory_order_release);
111 // unlock external lt
112 lt.unlock();
113 // suspend this fiber
114 if ( ! active_ctx->wait_until( timeout_time, lk) ) {
115 status = cv_status::timeout;
116 // relock local lk
117 lk.lock();
118 // remove from waiting-queue
119 wait_queue_.remove( * active_ctx);
120 // unlock local lk
121 lk.unlock();
122 }
123 // relock external again before returning
124 try {
125 lt.lock();
126 #if defined(BOOST_CONTEXT_HAS_CXXABI_H)
127 } catch ( abi::__forced_unwind const&) {
128 throw;
129 #endif
130 } catch (...) {
131 std::terminate();
132 }
133 // post-conditions
134 BOOST_ASSERT( ! active_ctx->wait_is_linked() );
135 return status;
136 }
137
138 template< typename LockType, typename Clock, typename Duration, typename Pred >
139 bool wait_until( LockType & lt,
140 std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
141 while ( ! pred() ) {
142 if ( cv_status::timeout == wait_until( lt, timeout_time) ) {
143 return pred();
144 }
145 }
146 return true;
147 }
148
149 template< typename LockType, typename Rep, typename Period >
150 cv_status wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration) {
151 return wait_until( lt,
152 std::chrono::steady_clock::now() + timeout_duration);
153 }
154
155 template< typename LockType, typename Rep, typename Period, typename Pred >
156 bool wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
157 return wait_until( lt,
158 std::chrono::steady_clock::now() + timeout_duration,
159 pred);
160 }
161 };
162
163 class BOOST_FIBERS_DECL condition_variable {
164 private:
165 condition_variable_any cnd_;
166
167 public:
168 condition_variable() = default;
169
170 condition_variable( condition_variable const&) = delete;
171 condition_variable & operator=( condition_variable const&) = delete;
172
173 void notify_one() noexcept {
174 cnd_.notify_one();
175 }
176
177 void notify_all() noexcept {
178 cnd_.notify_all();
179 }
180
181 void wait( std::unique_lock< mutex > & lt) {
182 // pre-condition
183 BOOST_ASSERT( lt.owns_lock() );
184 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
185 cnd_.wait( lt);
186 // post-condition
187 BOOST_ASSERT( lt.owns_lock() );
188 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
189 }
190
191 template< typename Pred >
192 void wait( std::unique_lock< mutex > & lt, Pred pred) {
193 // pre-condition
194 BOOST_ASSERT( lt.owns_lock() );
195 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
196 cnd_.wait( lt, pred);
197 // post-condition
198 BOOST_ASSERT( lt.owns_lock() );
199 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
200 }
201
202 template< typename Clock, typename Duration >
203 cv_status wait_until( std::unique_lock< mutex > & lt,
204 std::chrono::time_point< Clock, Duration > const& timeout_time) {
205 // pre-condition
206 BOOST_ASSERT( lt.owns_lock() );
207 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
208 cv_status result = cnd_.wait_until( lt, timeout_time);
209 // post-condition
210 BOOST_ASSERT( lt.owns_lock() );
211 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
212 return result;
213 }
214
215 template< typename Clock, typename Duration, typename Pred >
216 bool wait_until( std::unique_lock< mutex > & lt,
217 std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
218 // pre-condition
219 BOOST_ASSERT( lt.owns_lock() );
220 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
221 bool result = cnd_.wait_until( lt, timeout_time, pred);
222 // post-condition
223 BOOST_ASSERT( lt.owns_lock() );
224 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
225 return result;
226 }
227
228 template< typename Rep, typename Period >
229 cv_status wait_for( std::unique_lock< mutex > & lt,
230 std::chrono::duration< Rep, Period > const& timeout_duration) {
231 // pre-condition
232 BOOST_ASSERT( lt.owns_lock() );
233 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
234 cv_status result = cnd_.wait_for( lt, timeout_duration);
235 // post-condition
236 BOOST_ASSERT( lt.owns_lock() );
237 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
238 return result;
239 }
240
241 template< typename Rep, typename Period, typename Pred >
242 bool wait_for( std::unique_lock< mutex > & lt,
243 std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
244 // pre-condition
245 BOOST_ASSERT( lt.owns_lock() );
246 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
247 bool result = cnd_.wait_for( lt, timeout_duration, pred);
248 // post-condition
249 BOOST_ASSERT( lt.owns_lock() );
250 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
251 return result;
252 }
253 };
254
255 }}
256
257 #ifdef _MSC_VER
258 # pragma warning(pop)
259 #endif
260
261 #ifdef BOOST_HAS_ABI_HEADERS
262 # include BOOST_ABI_SUFFIX
263 #endif
264
265 #endif // BOOST_FIBERS_CONDITION_VARIABLE_H