]>
Commit | Line | Data |
---|---|---|
68a97d24 BK |
1 | // <condition_variable> -*- C++ -*- |
2 | ||
8d9254fc | 3 | // Copyright (C) 2008-2020 Free Software Foundation, Inc. |
68a97d24 BK |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
68a97d24 BK |
9 | // any later version. |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
748086b7 JJ |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
68a97d24 | 19 | |
748086b7 JJ |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
68a97d24 | 24 | |
f910786b | 25 | /** @file include/condition_variable |
68a97d24 BK |
26 | * This is a Standard C++ Library header. |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_CONDITION_VARIABLE | |
30 | #define _GLIBCXX_CONDITION_VARIABLE 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
734f5023 | 34 | #if __cplusplus < 201103L |
ab65a4c7 | 35 | # include <bits/c++0x_warning.h> |
57317d2a | 36 | #else |
68a97d24 | 37 | |
7b800287 | 38 | #include <chrono> |
942c4b32 | 39 | |
0c3e5dd1 | 40 | #include <bits/std_mutex.h> |
1fba0606 | 41 | #include <bits/unique_lock.h> |
3429db0f JW |
42 | #include <ext/concurrence.h> |
43 | #include <bits/alloc_traits.h> | |
44 | #include <bits/allocator.h> | |
45 | #include <bits/unique_ptr.h> | |
46 | #include <bits/shared_ptr.h> | |
c8c03058 | 47 | #include <bits/cxxabi_forced.h> |
68a97d24 | 48 | |
942c4b32 | 49 | #if __cplusplus > 201703L |
aa12ab2e | 50 | # include <stop_token> |
942c4b32 TR |
51 | #endif |
52 | ||
8ba7f29e | 53 | #if defined(_GLIBCXX_HAS_GTHREADS) |
7b800287 | 54 | |
12ffa228 BK |
55 | namespace std _GLIBCXX_VISIBILITY(default) |
56 | { | |
57 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
53dc5044 | 58 | |
5b9daa7e BK |
59 | /** |
60 | * @defgroup condition_variables Condition Variables | |
61 | * @ingroup concurrency | |
62 | * | |
63 | * Classes for condition_variable support. | |
64 | * @{ | |
65 | */ | |
66 | ||
cdf5f5a3 PC |
67 | /// cv_status |
68 | enum class cv_status { no_timeout, timeout }; | |
33ac58d5 | 69 | |
68a97d24 BK |
70 | /// condition_variable |
71 | class condition_variable | |
72 | { | |
ad4d1d21 MC |
73 | using steady_clock = chrono::steady_clock; |
74 | using system_clock = chrono::system_clock; | |
75 | #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT | |
76 | using __clock_t = steady_clock; | |
77 | #else | |
78 | using __clock_t = system_clock; | |
79 | #endif | |
f7459b6c | 80 | typedef __gthread_cond_t __native_type; |
b81e920e JW |
81 | |
82 | #ifdef __GTHREAD_COND_INIT | |
83 | __native_type _M_cond = __GTHREAD_COND_INIT; | |
84 | #else | |
f7459b6c | 85 | __native_type _M_cond; |
b81e920e | 86 | #endif |
88399079 | 87 | |
68a97d24 | 88 | public: |
f7459b6c | 89 | typedef __native_type* native_handle_type; |
68a97d24 | 90 | |
b81e920e JW |
91 | condition_variable() noexcept; |
92 | ~condition_variable() noexcept; | |
68a97d24 | 93 | |
7b800287 CF |
94 | condition_variable(const condition_variable&) = delete; |
95 | condition_variable& operator=(const condition_variable&) = delete; | |
96 | ||
d5cf2021 | 97 | void |
b81e920e | 98 | notify_one() noexcept; |
68a97d24 | 99 | |
d5cf2021 | 100 | void |
b81e920e | 101 | notify_all() noexcept; |
68a97d24 | 102 | |
d5cf2021 | 103 | void |
80400b04 | 104 | wait(unique_lock<mutex>& __lock) noexcept; |
68a97d24 BK |
105 | |
106 | template<typename _Predicate> | |
d5cf2021 | 107 | void |
68a97d24 BK |
108 | wait(unique_lock<mutex>& __lock, _Predicate __p) |
109 | { | |
110 | while (!__p()) | |
111 | wait(__lock); | |
112 | } | |
d5cf2021 | 113 | |
ad4d1d21 MC |
114 | #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT |
115 | template<typename _Duration> | |
116 | cv_status | |
117 | wait_until(unique_lock<mutex>& __lock, | |
118 | const chrono::time_point<steady_clock, _Duration>& __atime) | |
119 | { return __wait_until_impl(__lock, __atime); } | |
120 | #endif | |
121 | ||
88399079 | 122 | template<typename _Duration> |
cdf5f5a3 | 123 | cv_status |
88399079 | 124 | wait_until(unique_lock<mutex>& __lock, |
ad4d1d21 | 125 | const chrono::time_point<system_clock, _Duration>& __atime) |
88399079 CF |
126 | { return __wait_until_impl(__lock, __atime); } |
127 | ||
128 | template<typename _Clock, typename _Duration> | |
cdf5f5a3 | 129 | cv_status |
88399079 | 130 | wait_until(unique_lock<mutex>& __lock, |
7b800287 CF |
131 | const chrono::time_point<_Clock, _Duration>& __atime) |
132 | { | |
bf1fc37b JW |
133 | #if __cplusplus > 201703L |
134 | static_assert(chrono::is_clock_v<_Clock>); | |
135 | #endif | |
023cee96 PC |
136 | const typename _Clock::time_point __c_entry = _Clock::now(); |
137 | const __clock_t::time_point __s_entry = __clock_t::now(); | |
c25639b1 JW |
138 | const auto __delta = __atime - __c_entry; |
139 | const auto __s_atime = __s_entry + __delta; | |
7b800287 | 140 | |
2f593432 MC |
141 | if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout) |
142 | return cv_status::no_timeout; | |
143 | // We got a timeout when measured against __clock_t but | |
144 | // we need to check against the caller-supplied clock | |
145 | // to tell whether we should return a timeout. | |
146 | if (_Clock::now() < __atime) | |
147 | return cv_status::no_timeout; | |
148 | return cv_status::timeout; | |
7b800287 | 149 | } |
d3098c94 CF |
150 | |
151 | template<typename _Clock, typename _Duration, typename _Predicate> | |
152 | bool | |
153 | wait_until(unique_lock<mutex>& __lock, | |
154 | const chrono::time_point<_Clock, _Duration>& __atime, | |
88399079 CF |
155 | _Predicate __p) |
156 | { | |
f7459b6c | 157 | while (!__p()) |
cdf5f5a3 | 158 | if (wait_until(__lock, __atime) == cv_status::timeout) |
88399079 | 159 | return __p(); |
88399079 CF |
160 | return true; |
161 | } | |
d3098c94 CF |
162 | |
163 | template<typename _Rep, typename _Period> | |
cdf5f5a3 | 164 | cv_status |
d3098c94 | 165 | wait_for(unique_lock<mutex>& __lock, |
7b800287 | 166 | const chrono::duration<_Rep, _Period>& __rtime) |
83fd5e73 | 167 | { |
ad4d1d21 | 168 | using __dur = typename steady_clock::duration; |
83fd5e73 JW |
169 | auto __reltime = chrono::duration_cast<__dur>(__rtime); |
170 | if (__reltime < __rtime) | |
171 | ++__reltime; | |
ad4d1d21 | 172 | return wait_until(__lock, steady_clock::now() + __reltime); |
83fd5e73 | 173 | } |
d3098c94 CF |
174 | |
175 | template<typename _Rep, typename _Period, typename _Predicate> | |
176 | bool | |
177 | wait_for(unique_lock<mutex>& __lock, | |
178 | const chrono::duration<_Rep, _Period>& __rtime, | |
88399079 | 179 | _Predicate __p) |
83fd5e73 | 180 | { |
ad4d1d21 | 181 | using __dur = typename steady_clock::duration; |
83fd5e73 JW |
182 | auto __reltime = chrono::duration_cast<__dur>(__rtime); |
183 | if (__reltime < __rtime) | |
184 | ++__reltime; | |
ad4d1d21 | 185 | return wait_until(__lock, steady_clock::now() + __reltime, |
29b26763 | 186 | std::move(__p)); |
83fd5e73 | 187 | } |
68a97d24 | 188 | |
d5cf2021 BK |
189 | native_handle_type |
190 | native_handle() | |
7b800287 | 191 | { return &_M_cond; } |
68a97d24 BK |
192 | |
193 | private: | |
ad4d1d21 MC |
194 | #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT |
195 | template<typename _Dur> | |
196 | cv_status | |
197 | __wait_until_impl(unique_lock<mutex>& __lock, | |
198 | const chrono::time_point<steady_clock, _Dur>& __atime) | |
199 | { | |
200 | auto __s = chrono::time_point_cast<chrono::seconds>(__atime); | |
201 | auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); | |
202 | ||
203 | __gthread_time_t __ts = | |
204 | { | |
205 | static_cast<std::time_t>(__s.time_since_epoch().count()), | |
206 | static_cast<long>(__ns.count()) | |
207 | }; | |
208 | ||
209 | pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(), | |
210 | CLOCK_MONOTONIC, | |
211 | &__ts); | |
212 | ||
213 | return (steady_clock::now() < __atime | |
214 | ? cv_status::no_timeout : cv_status::timeout); | |
215 | } | |
216 | #endif | |
217 | ||
c25639b1 | 218 | template<typename _Dur> |
cdf5f5a3 | 219 | cv_status |
88399079 | 220 | __wait_until_impl(unique_lock<mutex>& __lock, |
ad4d1d21 | 221 | const chrono::time_point<system_clock, _Dur>& __atime) |
88399079 | 222 | { |
c25639b1 JW |
223 | auto __s = chrono::time_point_cast<chrono::seconds>(__atime); |
224 | auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); | |
d5cf2021 BK |
225 | |
226 | __gthread_time_t __ts = | |
227 | { | |
228 | static_cast<std::time_t>(__s.time_since_epoch().count()), | |
229 | static_cast<long>(__ns.count()) | |
230 | }; | |
231 | ||
232 | __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), | |
233 | &__ts); | |
234 | ||
ad4d1d21 | 235 | return (system_clock::now() < __atime |
cdf5f5a3 | 236 | ? cv_status::no_timeout : cv_status::timeout); |
88399079 | 237 | } |
68a97d24 BK |
238 | }; |
239 | ||
9db7c931 JW |
240 | void |
241 | notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>); | |
242 | ||
243 | struct __at_thread_exit_elt | |
244 | { | |
245 | __at_thread_exit_elt* _M_next; | |
246 | void (*_M_cb)(void*); | |
247 | }; | |
248 | ||
3429db0f JW |
249 | inline namespace _V2 { |
250 | ||
68a97d24 | 251 | /// condition_variable_any |
b7200e3f | 252 | // Like above, but mutex is not required to have try_lock. |
68a97d24 BK |
253 | class condition_variable_any |
254 | { | |
ad4d1d21 MC |
255 | #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT |
256 | using __clock_t = chrono::steady_clock; | |
257 | #else | |
258 | using __clock_t = chrono::system_clock; | |
259 | #endif | |
b7200e3f | 260 | condition_variable _M_cond; |
3429db0f | 261 | shared_ptr<mutex> _M_mutex; |
f7459b6c | 262 | |
7f426c93 JW |
263 | // scoped unlock - unlocks in ctor, re-locks in dtor |
264 | template<typename _Lock> | |
265 | struct _Unlock | |
266 | { | |
267 | explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); } | |
268 | ||
b0c21108 JW |
269 | #pragma GCC diagnostic push |
270 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
7f426c93 JW |
271 | ~_Unlock() noexcept(false) |
272 | { | |
273 | if (uncaught_exception()) | |
315eb4bb JW |
274 | { |
275 | __try | |
276 | { _M_lock.lock(); } | |
277 | __catch(const __cxxabiv1::__forced_unwind&) | |
278 | { __throw_exception_again; } | |
279 | __catch(...) | |
280 | { } | |
281 | } | |
7f426c93 JW |
282 | else |
283 | _M_lock.lock(); | |
284 | } | |
b0c21108 | 285 | #pragma GCC diagnostic pop |
7f426c93 JW |
286 | |
287 | _Unlock(const _Unlock&) = delete; | |
288 | _Unlock& operator=(const _Unlock&) = delete; | |
289 | ||
290 | _Lock& _M_lock; | |
291 | }; | |
292 | ||
68a97d24 | 293 | public: |
3429db0f JW |
294 | condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { } |
295 | ~condition_variable_any() = default; | |
d5cf2021 | 296 | |
7b800287 CF |
297 | condition_variable_any(const condition_variable_any&) = delete; |
298 | condition_variable_any& operator=(const condition_variable_any&) = delete; | |
68a97d24 | 299 | |
d5cf2021 | 300 | void |
b81e920e | 301 | notify_one() noexcept |
b7200e3f | 302 | { |
3429db0f | 303 | lock_guard<mutex> __lock(*_M_mutex); |
b7200e3f JW |
304 | _M_cond.notify_one(); |
305 | } | |
68a97d24 | 306 | |
d5cf2021 | 307 | void |
b81e920e | 308 | notify_all() noexcept |
b7200e3f | 309 | { |
3429db0f | 310 | lock_guard<mutex> __lock(*_M_mutex); |
b7200e3f JW |
311 | _M_cond.notify_all(); |
312 | } | |
68a97d24 BK |
313 | |
314 | template<typename _Lock> | |
d5cf2021 | 315 | void |
b7200e3f JW |
316 | wait(_Lock& __lock) |
317 | { | |
3429db0f JW |
318 | shared_ptr<mutex> __mutex = _M_mutex; |
319 | unique_lock<mutex> __my_lock(*__mutex); | |
7f426c93 | 320 | _Unlock<_Lock> __unlock(__lock); |
3429db0f JW |
321 | // *__mutex must be unlocked before re-locking __lock so move |
322 | // ownership of *__mutex lock to an object with shorter lifetime. | |
5d020aa2 JW |
323 | unique_lock<mutex> __my_lock2(std::move(__my_lock)); |
324 | _M_cond.wait(__my_lock2); | |
b7200e3f | 325 | } |
33ac58d5 | 326 | |
68a97d24 BK |
327 | |
328 | template<typename _Lock, typename _Predicate> | |
d5cf2021 | 329 | void |
cdf5f5a3 PC |
330 | wait(_Lock& __lock, _Predicate __p) |
331 | { | |
332 | while (!__p()) | |
333 | wait(__lock); | |
334 | } | |
68a97d24 | 335 | |
d3098c94 | 336 | template<typename _Lock, typename _Clock, typename _Duration> |
cdf5f5a3 | 337 | cv_status |
d3098c94 | 338 | wait_until(_Lock& __lock, |
b7200e3f JW |
339 | const chrono::time_point<_Clock, _Duration>& __atime) |
340 | { | |
3429db0f JW |
341 | shared_ptr<mutex> __mutex = _M_mutex; |
342 | unique_lock<mutex> __my_lock(*__mutex); | |
7f426c93 | 343 | _Unlock<_Lock> __unlock(__lock); |
3429db0f JW |
344 | // *__mutex must be unlocked before re-locking __lock so move |
345 | // ownership of *__mutex lock to an object with shorter lifetime. | |
7f426c93 JW |
346 | unique_lock<mutex> __my_lock2(std::move(__my_lock)); |
347 | return _M_cond.wait_until(__my_lock2, __atime); | |
b7200e3f | 348 | } |
68a97d24 | 349 | |
d5cf2021 | 350 | template<typename _Lock, typename _Clock, |
d3098c94 | 351 | typename _Duration, typename _Predicate> |
d5cf2021 | 352 | bool |
d3098c94 CF |
353 | wait_until(_Lock& __lock, |
354 | const chrono::time_point<_Clock, _Duration>& __atime, | |
cdf5f5a3 PC |
355 | _Predicate __p) |
356 | { | |
357 | while (!__p()) | |
358 | if (wait_until(__lock, __atime) == cv_status::timeout) | |
359 | return __p(); | |
360 | return true; | |
361 | } | |
d5cf2021 | 362 | |
d3098c94 | 363 | template<typename _Lock, typename _Rep, typename _Period> |
cdf5f5a3 | 364 | cv_status |
b7200e3f JW |
365 | wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) |
366 | { return wait_until(__lock, __clock_t::now() + __rtime); } | |
d3098c94 CF |
367 | |
368 | template<typename _Lock, typename _Rep, | |
369 | typename _Period, typename _Predicate> | |
370 | bool | |
d5cf2021 | 371 | wait_for(_Lock& __lock, |
b7200e3f JW |
372 | const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p) |
373 | { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } | |
942c4b32 TR |
374 | |
375 | #ifdef __cpp_lib_jthread | |
376 | template <class _Lock, class _Predicate> | |
9e3c1eb7 TR |
377 | bool wait(_Lock& __lock, |
378 | stop_token __stoken, | |
379 | _Predicate __p) | |
942c4b32 TR |
380 | { |
381 | if (__stoken.stop_requested()) | |
382 | { | |
383 | return __p(); | |
384 | } | |
385 | ||
386 | std::stop_callback __cb(__stoken, [this] { notify_all(); }); | |
387 | shared_ptr<mutex> __mutex = _M_mutex; | |
388 | while (!__p()) | |
389 | { | |
390 | unique_lock<mutex> __my_lock(*__mutex); | |
391 | if (__stoken.stop_requested()) | |
392 | { | |
393 | return false; | |
394 | } | |
395 | // *__mutex must be unlocked before re-locking __lock so move | |
396 | // ownership of *__mutex lock to an object with shorter lifetime. | |
397 | _Unlock<_Lock> __unlock(__lock); | |
398 | unique_lock<mutex> __my_lock2(std::move(__my_lock)); | |
399 | _M_cond.wait(__my_lock2); | |
400 | } | |
401 | return true; | |
402 | } | |
403 | ||
404 | template <class _Lock, class _Clock, class _Duration, class _Predicate> | |
9e3c1eb7 TR |
405 | bool wait_until(_Lock& __lock, |
406 | stop_token __stoken, | |
407 | const chrono::time_point<_Clock, _Duration>& __abs_time, | |
408 | _Predicate __p) | |
942c4b32 TR |
409 | { |
410 | if (__stoken.stop_requested()) | |
411 | { | |
412 | return __p(); | |
413 | } | |
414 | ||
415 | std::stop_callback __cb(__stoken, [this] { notify_all(); }); | |
416 | shared_ptr<mutex> __mutex = _M_mutex; | |
417 | while (!__p()) | |
418 | { | |
419 | bool __stop; | |
420 | { | |
421 | unique_lock<mutex> __my_lock(*__mutex); | |
422 | if (__stoken.stop_requested()) | |
423 | { | |
424 | return false; | |
425 | } | |
426 | _Unlock<_Lock> __u(__lock); | |
427 | unique_lock<mutex> __my_lock2(std::move(__my_lock)); | |
428 | const auto __status = _M_cond.wait_until(__my_lock2, __abs_time); | |
429 | __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested(); | |
430 | } | |
431 | if (__stop) | |
432 | { | |
433 | return __p(); | |
434 | } | |
435 | } | |
436 | return true; | |
437 | } | |
438 | ||
439 | template <class _Lock, class _Rep, class _Period, class _Predicate> | |
9e3c1eb7 TR |
440 | bool wait_for(_Lock& __lock, |
441 | stop_token __stoken, | |
442 | const chrono::duration<_Rep, _Period>& __rel_time, | |
443 | _Predicate __p) | |
942c4b32 TR |
444 | { |
445 | auto __abst = std::chrono::steady_clock::now() + __rel_time; | |
9e3c1eb7 TR |
446 | return wait_until(__lock, |
447 | std::move(__stoken), | |
448 | __abst, | |
449 | std::move(__p)); | |
942c4b32 TR |
450 | } |
451 | #endif | |
68a97d24 | 452 | }; |
5b9daa7e | 453 | |
3429db0f JW |
454 | } // end inline namespace |
455 | ||
5b9daa7e | 456 | // @} group condition_variables |
12ffa228 BK |
457 | _GLIBCXX_END_NAMESPACE_VERSION |
458 | } // namespace | |
68a97d24 | 459 | |
8ba7f29e | 460 | #endif // _GLIBCXX_HAS_GTHREADS |
734f5023 | 461 | #endif // C++11 |
57317d2a | 462 | #endif // _GLIBCXX_CONDITION_VARIABLE |