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