]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fiber/include/boost/fiber/condition_variable.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / fiber / include / 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 wait_queue_t wait_queue_{};
49 detail::spinlock wait_queue_splk_{};
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 * 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( ! ctx->wait_is_linked() );
72 ctx->wait_link( wait_queue_);
73 // unlock external lt
74 lt.unlock();
75 // suspend this fiber
76 ctx->suspend( lk);
77 // relock local lk
78 lk.lock();
79 // remove from waiting-queue
80 ctx->wait_unlink();
81 // unlock local lk
82 lk.unlock();
83 // relock external again before returning
84 try {
85 lt.lock();
86 } catch (...) {
87 std::terminate();
88 }
89 // post-conditions
90 BOOST_ASSERT( ! 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 cv_status status = cv_status::no_timeout;
103 std::chrono::steady_clock::time_point timeout_time(
104 detail::convert( timeout_time_) );
105 context * ctx = context::active();
106 // atomically call lt.unlock() and block on *this
107 // store this fiber in waiting-queue
108 detail::spinlock_lock lk( wait_queue_splk_);
109 BOOST_ASSERT( ! ctx->wait_is_linked() );
110 ctx->wait_link( wait_queue_);
111 // unlock external lt
112 lt.unlock();
113 // suspend this fiber
114 if ( ! ctx->wait_until( timeout_time, lk) ) {
115 status = cv_status::timeout;
116 }
117 // relock local lk
118 lk.lock();
119 // remove from waiting-queue
120 ctx->wait_unlink();
121 // unlock local lk
122 lk.unlock();
123 // relock external again before returning
124 try {
125 lt.lock();
126 } catch (...) {
127 std::terminate();
128 }
129 // post-conditions
130 BOOST_ASSERT( ! ctx->wait_is_linked() );
131 return status;
132 }
133
134 template< typename LockType, typename Clock, typename Duration, typename Pred >
135 bool wait_until( LockType & lt,
136 std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
137 while ( ! pred() ) {
138 if ( cv_status::timeout == wait_until( lt, timeout_time) ) {
139 return pred();
140 }
141 }
142 return true;
143 }
144
145 template< typename LockType, typename Rep, typename Period >
146 cv_status wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration) {
147 return wait_until( lt,
148 std::chrono::steady_clock::now() + timeout_duration);
149 }
150
151 template< typename LockType, typename Rep, typename Period, typename Pred >
152 bool wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
153 return wait_until( lt,
154 std::chrono::steady_clock::now() + timeout_duration,
155 pred);
156 }
157 };
158
159 class BOOST_FIBERS_DECL condition_variable {
160 private:
161 condition_variable_any cnd_;
162
163 public:
164 condition_variable() = default;
165
166 condition_variable( condition_variable const&) = delete;
167 condition_variable & operator=( condition_variable const&) = delete;
168
169 void notify_one() noexcept {
170 cnd_.notify_one();
171 }
172
173 void notify_all() noexcept {
174 cnd_.notify_all();
175 }
176
177 void wait( std::unique_lock< mutex > & lt) {
178 // pre-condition
179 BOOST_ASSERT( lt.owns_lock() );
180 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
181 cnd_.wait( lt);
182 // post-condition
183 BOOST_ASSERT( lt.owns_lock() );
184 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
185 }
186
187 template< typename Pred >
188 void wait( std::unique_lock< mutex > & lt, Pred pred) {
189 // pre-condition
190 BOOST_ASSERT( lt.owns_lock() );
191 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
192 cnd_.wait( lt, pred);
193 // post-condition
194 BOOST_ASSERT( lt.owns_lock() );
195 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
196 }
197
198 template< typename Clock, typename Duration >
199 cv_status wait_until( std::unique_lock< mutex > & lt,
200 std::chrono::time_point< Clock, Duration > const& timeout_time) {
201 // pre-condition
202 BOOST_ASSERT( lt.owns_lock() );
203 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
204 cv_status result = cnd_.wait_until( lt, timeout_time);
205 // post-condition
206 BOOST_ASSERT( lt.owns_lock() );
207 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
208 return result;
209 }
210
211 template< typename Clock, typename Duration, typename Pred >
212 bool wait_until( std::unique_lock< mutex > & lt,
213 std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
214 // pre-condition
215 BOOST_ASSERT( lt.owns_lock() );
216 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
217 bool result = cnd_.wait_until( lt, timeout_time, pred);
218 // post-condition
219 BOOST_ASSERT( lt.owns_lock() );
220 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
221 return result;
222 }
223
224 template< typename Rep, typename Period >
225 cv_status wait_for( std::unique_lock< mutex > & lt,
226 std::chrono::duration< Rep, Period > const& timeout_duration) {
227 // pre-condition
228 BOOST_ASSERT( lt.owns_lock() );
229 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
230 cv_status result = cnd_.wait_for( lt, timeout_duration);
231 // post-condition
232 BOOST_ASSERT( lt.owns_lock() );
233 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
234 return result;
235 }
236
237 template< typename Rep, typename Period, typename Pred >
238 bool wait_for( std::unique_lock< mutex > & lt,
239 std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
240 // pre-condition
241 BOOST_ASSERT( lt.owns_lock() );
242 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
243 bool result = cnd_.wait_for( lt, timeout_duration, pred);
244 // post-condition
245 BOOST_ASSERT( lt.owns_lock() );
246 BOOST_ASSERT( context::active() == lt.mutex()->owner_);
247 return result;
248 }
249 };
250
251 }}
252
253 #ifdef _MSC_VER
254 # pragma warning(pop)
255 #endif
256
257 #ifdef BOOST_HAS_ABI_HEADERS
258 # include BOOST_ABI_SUFFIX
259 #endif
260
261 #endif // BOOST_FIBERS_CONDITION_VARIABLE_H