]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/std/condition_variable
libstdc++: Encapsulate __gthread_cond_t as std::__condvar
[thirdparty/gcc.git] / libstdc++-v3 / include / std / condition_variable
CommitLineData
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 42#include <bits/alloc_traits.h>
3429db0f 43#include <bits/shared_ptr.h>
c8c03058 44#include <bits/cxxabi_forced.h>
68a97d24 45
942c4b32 46#if __cplusplus > 201703L
aa12ab2e 47# include <stop_token>
942c4b32
TR
48#endif
49
8ba7f29e 50#if defined(_GLIBCXX_HAS_GTHREADS)
7b800287 51
12ffa228
BK
52namespace std _GLIBCXX_VISIBILITY(default)
53{
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
53dc5044 55
5b9daa7e
BK
56 /**
57 * @defgroup condition_variables Condition Variables
58 * @ingroup concurrency
59 *
60 * Classes for condition_variable support.
61 * @{
62 */
63
cdf5f5a3
PC
64 /// cv_status
65 enum class cv_status { no_timeout, timeout };
33ac58d5 66
68a97d24
BK
67 /// condition_variable
68 class condition_variable
69 {
ad4d1d21
MC
70 using steady_clock = chrono::steady_clock;
71 using system_clock = chrono::system_clock;
72#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
73 using __clock_t = steady_clock;
74#else
75 using __clock_t = system_clock;
76#endif
b81e920e 77
7d2a98a7 78 __condvar _M_cond;
88399079 79
68a97d24 80 public:
7d2a98a7 81 typedef __gthread_cond_t* native_handle_type;
68a97d24 82
b81e920e
JW
83 condition_variable() noexcept;
84 ~condition_variable() noexcept;
68a97d24 85
7b800287
CF
86 condition_variable(const condition_variable&) = delete;
87 condition_variable& operator=(const condition_variable&) = delete;
88
d5cf2021 89 void
b81e920e 90 notify_one() noexcept;
68a97d24 91
d5cf2021 92 void
b81e920e 93 notify_all() noexcept;
68a97d24 94
d5cf2021 95 void
80400b04 96 wait(unique_lock<mutex>& __lock) noexcept;
68a97d24
BK
97
98 template<typename _Predicate>
d5cf2021 99 void
68a97d24
BK
100 wait(unique_lock<mutex>& __lock, _Predicate __p)
101 {
102 while (!__p())
103 wait(__lock);
104 }
d5cf2021 105
ad4d1d21
MC
106#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
107 template<typename _Duration>
108 cv_status
109 wait_until(unique_lock<mutex>& __lock,
110 const chrono::time_point<steady_clock, _Duration>& __atime)
111 { return __wait_until_impl(__lock, __atime); }
112#endif
113
88399079 114 template<typename _Duration>
cdf5f5a3 115 cv_status
88399079 116 wait_until(unique_lock<mutex>& __lock,
ad4d1d21 117 const chrono::time_point<system_clock, _Duration>& __atime)
88399079
CF
118 { return __wait_until_impl(__lock, __atime); }
119
120 template<typename _Clock, typename _Duration>
cdf5f5a3 121 cv_status
88399079 122 wait_until(unique_lock<mutex>& __lock,
7b800287
CF
123 const chrono::time_point<_Clock, _Duration>& __atime)
124 {
bf1fc37b
JW
125#if __cplusplus > 201703L
126 static_assert(chrono::is_clock_v<_Clock>);
127#endif
e05ff300 128 using __s_dur = typename __clock_t::duration;
023cee96
PC
129 const typename _Clock::time_point __c_entry = _Clock::now();
130 const __clock_t::time_point __s_entry = __clock_t::now();
c25639b1 131 const auto __delta = __atime - __c_entry;
e05ff300
MC
132 const auto __s_atime = __s_entry +
133 chrono::__detail::ceil<__s_dur>(__delta);
7b800287 134
2f593432
MC
135 if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout)
136 return cv_status::no_timeout;
137 // We got a timeout when measured against __clock_t but
138 // we need to check against the caller-supplied clock
139 // to tell whether we should return a timeout.
140 if (_Clock::now() < __atime)
141 return cv_status::no_timeout;
142 return cv_status::timeout;
7b800287 143 }
d3098c94
CF
144
145 template<typename _Clock, typename _Duration, typename _Predicate>
146 bool
147 wait_until(unique_lock<mutex>& __lock,
148 const chrono::time_point<_Clock, _Duration>& __atime,
88399079
CF
149 _Predicate __p)
150 {
f7459b6c 151 while (!__p())
cdf5f5a3 152 if (wait_until(__lock, __atime) == cv_status::timeout)
88399079 153 return __p();
88399079
CF
154 return true;
155 }
d3098c94
CF
156
157 template<typename _Rep, typename _Period>
cdf5f5a3 158 cv_status
d3098c94 159 wait_for(unique_lock<mutex>& __lock,
7b800287 160 const chrono::duration<_Rep, _Period>& __rtime)
83fd5e73 161 {
ad4d1d21 162 using __dur = typename steady_clock::duration;
e05ff300
MC
163 return wait_until(__lock,
164 steady_clock::now() +
165 chrono::__detail::ceil<__dur>(__rtime));
83fd5e73 166 }
d3098c94
CF
167
168 template<typename _Rep, typename _Period, typename _Predicate>
169 bool
170 wait_for(unique_lock<mutex>& __lock,
171 const chrono::duration<_Rep, _Period>& __rtime,
88399079 172 _Predicate __p)
83fd5e73 173 {
ad4d1d21 174 using __dur = typename steady_clock::duration;
e05ff300
MC
175 return wait_until(__lock,
176 steady_clock::now() +
177 chrono::__detail::ceil<__dur>(__rtime),
29b26763 178 std::move(__p));
83fd5e73 179 }
68a97d24 180
d5cf2021
BK
181 native_handle_type
182 native_handle()
7d2a98a7 183 { return _M_cond.native_handle(); }
68a97d24
BK
184
185 private:
ad4d1d21
MC
186#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
187 template<typename _Dur>
188 cv_status
189 __wait_until_impl(unique_lock<mutex>& __lock,
190 const chrono::time_point<steady_clock, _Dur>& __atime)
191 {
192 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
193 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
194
195 __gthread_time_t __ts =
196 {
197 static_cast<std::time_t>(__s.time_since_epoch().count()),
198 static_cast<long>(__ns.count())
199 };
200
7d2a98a7 201 _M_cond.wait_until(*__lock.mutex(), CLOCK_MONOTONIC, __ts);
ad4d1d21
MC
202
203 return (steady_clock::now() < __atime
204 ? cv_status::no_timeout : cv_status::timeout);
205 }
206#endif
207
c25639b1 208 template<typename _Dur>
cdf5f5a3 209 cv_status
88399079 210 __wait_until_impl(unique_lock<mutex>& __lock,
ad4d1d21 211 const chrono::time_point<system_clock, _Dur>& __atime)
88399079 212 {
c25639b1
JW
213 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
214 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
d5cf2021
BK
215
216 __gthread_time_t __ts =
217 {
218 static_cast<std::time_t>(__s.time_since_epoch().count()),
219 static_cast<long>(__ns.count())
220 };
221
7d2a98a7 222 _M_cond.wait_until(*__lock.mutex(), __ts);
d5cf2021 223
ad4d1d21 224 return (system_clock::now() < __atime
cdf5f5a3 225 ? cv_status::no_timeout : cv_status::timeout);
88399079 226 }
68a97d24
BK
227 };
228
9db7c931
JW
229 void
230 notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
231
232 struct __at_thread_exit_elt
233 {
234 __at_thread_exit_elt* _M_next;
235 void (*_M_cb)(void*);
236 };
237
3429db0f
JW
238 inline namespace _V2 {
239
68a97d24 240 /// condition_variable_any
b7200e3f 241 // Like above, but mutex is not required to have try_lock.
68a97d24
BK
242 class condition_variable_any
243 {
ad4d1d21
MC
244#ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
245 using __clock_t = chrono::steady_clock;
246#else
247 using __clock_t = chrono::system_clock;
248#endif
b7200e3f 249 condition_variable _M_cond;
3429db0f 250 shared_ptr<mutex> _M_mutex;
f7459b6c 251
7f426c93
JW
252 // scoped unlock - unlocks in ctor, re-locks in dtor
253 template<typename _Lock>
254 struct _Unlock
255 {
256 explicit _Unlock(_Lock& __lk) : _M_lock(__lk) { __lk.unlock(); }
257
0943b558
JW
258#pragma GCC diagnostic push
259#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
7f426c93
JW
260 ~_Unlock() noexcept(false)
261 {
262 if (uncaught_exception())
315eb4bb
JW
263 {
264 __try
265 { _M_lock.lock(); }
266 __catch(const __cxxabiv1::__forced_unwind&)
267 { __throw_exception_again; }
268 __catch(...)
269 { }
270 }
7f426c93
JW
271 else
272 _M_lock.lock();
273 }
0943b558 274#pragma GCC diagnostic pop
7f426c93
JW
275
276 _Unlock(const _Unlock&) = delete;
277 _Unlock& operator=(const _Unlock&) = delete;
278
279 _Lock& _M_lock;
280 };
281
68a97d24 282 public:
3429db0f
JW
283 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { }
284 ~condition_variable_any() = default;
d5cf2021 285
7b800287
CF
286 condition_variable_any(const condition_variable_any&) = delete;
287 condition_variable_any& operator=(const condition_variable_any&) = delete;
68a97d24 288
d5cf2021 289 void
b81e920e 290 notify_one() noexcept
b7200e3f 291 {
3429db0f 292 lock_guard<mutex> __lock(*_M_mutex);
b7200e3f
JW
293 _M_cond.notify_one();
294 }
68a97d24 295
d5cf2021 296 void
b81e920e 297 notify_all() noexcept
b7200e3f 298 {
3429db0f 299 lock_guard<mutex> __lock(*_M_mutex);
b7200e3f
JW
300 _M_cond.notify_all();
301 }
68a97d24
BK
302
303 template<typename _Lock>
d5cf2021 304 void
b7200e3f
JW
305 wait(_Lock& __lock)
306 {
3429db0f
JW
307 shared_ptr<mutex> __mutex = _M_mutex;
308 unique_lock<mutex> __my_lock(*__mutex);
7f426c93 309 _Unlock<_Lock> __unlock(__lock);
3429db0f
JW
310 // *__mutex must be unlocked before re-locking __lock so move
311 // ownership of *__mutex lock to an object with shorter lifetime.
5d020aa2
JW
312 unique_lock<mutex> __my_lock2(std::move(__my_lock));
313 _M_cond.wait(__my_lock2);
b7200e3f 314 }
33ac58d5 315
68a97d24
BK
316
317 template<typename _Lock, typename _Predicate>
d5cf2021 318 void
cdf5f5a3
PC
319 wait(_Lock& __lock, _Predicate __p)
320 {
321 while (!__p())
322 wait(__lock);
323 }
68a97d24 324
d3098c94 325 template<typename _Lock, typename _Clock, typename _Duration>
cdf5f5a3 326 cv_status
d3098c94 327 wait_until(_Lock& __lock,
b7200e3f
JW
328 const chrono::time_point<_Clock, _Duration>& __atime)
329 {
3429db0f
JW
330 shared_ptr<mutex> __mutex = _M_mutex;
331 unique_lock<mutex> __my_lock(*__mutex);
7f426c93 332 _Unlock<_Lock> __unlock(__lock);
3429db0f
JW
333 // *__mutex must be unlocked before re-locking __lock so move
334 // ownership of *__mutex lock to an object with shorter lifetime.
7f426c93
JW
335 unique_lock<mutex> __my_lock2(std::move(__my_lock));
336 return _M_cond.wait_until(__my_lock2, __atime);
b7200e3f 337 }
68a97d24 338
d5cf2021 339 template<typename _Lock, typename _Clock,
d3098c94 340 typename _Duration, typename _Predicate>
d5cf2021 341 bool
d3098c94
CF
342 wait_until(_Lock& __lock,
343 const chrono::time_point<_Clock, _Duration>& __atime,
cdf5f5a3
PC
344 _Predicate __p)
345 {
346 while (!__p())
347 if (wait_until(__lock, __atime) == cv_status::timeout)
348 return __p();
349 return true;
350 }
d5cf2021 351
d3098c94 352 template<typename _Lock, typename _Rep, typename _Period>
cdf5f5a3 353 cv_status
b7200e3f
JW
354 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)
355 { return wait_until(__lock, __clock_t::now() + __rtime); }
d3098c94
CF
356
357 template<typename _Lock, typename _Rep,
358 typename _Period, typename _Predicate>
359 bool
d5cf2021 360 wait_for(_Lock& __lock,
b7200e3f
JW
361 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p)
362 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); }
942c4b32
TR
363
364#ifdef __cpp_lib_jthread
365 template <class _Lock, class _Predicate>
9e3c1eb7
TR
366 bool wait(_Lock& __lock,
367 stop_token __stoken,
368 _Predicate __p)
942c4b32
TR
369 {
370 if (__stoken.stop_requested())
371 {
372 return __p();
373 }
374
375 std::stop_callback __cb(__stoken, [this] { notify_all(); });
376 shared_ptr<mutex> __mutex = _M_mutex;
377 while (!__p())
378 {
379 unique_lock<mutex> __my_lock(*__mutex);
380 if (__stoken.stop_requested())
381 {
382 return false;
383 }
384 // *__mutex must be unlocked before re-locking __lock so move
385 // ownership of *__mutex lock to an object with shorter lifetime.
386 _Unlock<_Lock> __unlock(__lock);
387 unique_lock<mutex> __my_lock2(std::move(__my_lock));
388 _M_cond.wait(__my_lock2);
389 }
390 return true;
391 }
392
393 template <class _Lock, class _Clock, class _Duration, class _Predicate>
9e3c1eb7
TR
394 bool wait_until(_Lock& __lock,
395 stop_token __stoken,
396 const chrono::time_point<_Clock, _Duration>& __abs_time,
397 _Predicate __p)
942c4b32
TR
398 {
399 if (__stoken.stop_requested())
400 {
401 return __p();
402 }
403
404 std::stop_callback __cb(__stoken, [this] { notify_all(); });
405 shared_ptr<mutex> __mutex = _M_mutex;
406 while (!__p())
407 {
408 bool __stop;
409 {
410 unique_lock<mutex> __my_lock(*__mutex);
411 if (__stoken.stop_requested())
412 {
413 return false;
414 }
415 _Unlock<_Lock> __u(__lock);
416 unique_lock<mutex> __my_lock2(std::move(__my_lock));
417 const auto __status = _M_cond.wait_until(__my_lock2, __abs_time);
418 __stop = (__status == std::cv_status::timeout) || __stoken.stop_requested();
419 }
420 if (__stop)
421 {
422 return __p();
423 }
424 }
425 return true;
426 }
427
428 template <class _Lock, class _Rep, class _Period, class _Predicate>
9e3c1eb7
TR
429 bool wait_for(_Lock& __lock,
430 stop_token __stoken,
431 const chrono::duration<_Rep, _Period>& __rel_time,
432 _Predicate __p)
942c4b32
TR
433 {
434 auto __abst = std::chrono::steady_clock::now() + __rel_time;
9e3c1eb7
TR
435 return wait_until(__lock,
436 std::move(__stoken),
437 __abst,
438 std::move(__p));
942c4b32
TR
439 }
440#endif
68a97d24 441 };
5b9daa7e 442
3429db0f
JW
443 } // end inline namespace
444
5b9daa7e 445 // @} group condition_variables
12ffa228
BK
446_GLIBCXX_END_NAMESPACE_VERSION
447} // namespace
68a97d24 448
8ba7f29e 449#endif // _GLIBCXX_HAS_GTHREADS
734f5023 450#endif // C++11
57317d2a 451#endif // _GLIBCXX_CONDITION_VARIABLE