1// <condition_variable> -*- C++ -*- 
2 
3// Copyright (C) 2008-2021 Free Software Foundation, Inc. 
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 
8// Free Software Foundation; either version 3, or (at your option) 
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 
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. 
19 
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/>. 
24 
25/** @file include/condition_variable 
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 
34#if __cplusplus < 201103L 
35# include <bits/c++0x_warning.h> 
36#else 
37 
38#include <chrono> 
39 
40#include <bits/std_mutex.h> 
41#include <bits/unique_lock.h> 
42#include <bits/alloc_traits.h> 
43#include <bits/shared_ptr.h> 
44#include <bits/cxxabi_forced.h> 
45 
46#if __cplusplus > 201703L 
47# include <stop_token> 
48#endif 
49 
50#if defined(_GLIBCXX_HAS_GTHREADS) 
51 
52namespace std _GLIBCXX_VISIBILITY(default
53
54_GLIBCXX_BEGIN_NAMESPACE_VERSION 
55 
56 /** 
57 * @defgroup condition_variables Condition Variables 
58 * @ingroup concurrency 
59 * 
60 * Classes for condition_variable support. 
61 * @{ 
62 */ 
63 
64 /// cv_status 
65 enum class cv_status { no_timeout, timeout }; 
66 
67 /// condition_variable 
68 class condition_variable 
69
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 
77 
78 __condvar _M_cond
79 
80 public
81 typedef __gthread_cond_t* native_handle_type
82 
83 condition_variable() noexcept
84 ~condition_variable() noexcept
85 
86 condition_variable(const condition_variable&) = delete
87 condition_variable& operator=(const condition_variable&) = delete
88 
89 void 
90 notify_one() noexcept
91 
92 void 
93 notify_all() noexcept
94 
95 void 
96 wait(unique_lock<mutex>& __lock) noexcept
97 
98 template<typename _Predicate> 
99 void 
100 wait(unique_lock<mutex>& __lock, _Predicate __p
101
102 while (!__p()) 
103 wait(__lock); 
104
105 
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 
114 template<typename _Duration> 
115 cv_status 
116 wait_until(unique_lock<mutex>& __lock
117 const chrono::time_point<system_clock, _Duration>& __atime
118 { return __wait_until_impl(__lock, __atime); } 
119 
120 template<typename _Clock, typename _Duration> 
121 cv_status 
122 wait_until(unique_lock<mutex>& __lock
123 const chrono::time_point<_Clock, _Duration>& __atime
124
125#if __cplusplus > 201703L 
126 static_assert(chrono::is_clock_v<_Clock>); 
127#endif 
128 using __s_dur = typename __clock_t::duration
129 const typename _Clock::time_point __c_entry = _Clock::now(); 
130 const __clock_t::time_point __s_entry = __clock_t::now(); 
131 const auto __delta = __atime - __c_entry
132 const auto __s_atime = __s_entry
133 chrono::__detail::ceil<__s_dur>(__delta); 
134 
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
143
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
149 _Predicate __p
150
151 while (!__p()) 
152 if (wait_until(__lock, __atime) == cv_status::timeout
153 return __p(); 
154 return true
155
156 
157 template<typename _Rep, typename _Period> 
158 cv_status 
159 wait_for(unique_lock<mutex>& __lock
160 const chrono::duration<_Rep, _Period>& __rtime
161
162 using __dur = typename steady_clock::duration
163 return wait_until(__lock
164 steady_clock::now() + 
165 chrono::__detail::ceil<__dur>(__rtime)); 
166
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
172 _Predicate __p
173
174 using __dur = typename steady_clock::duration
175 return wait_until(__lock
176 steady_clock::now() + 
177 chrono::__detail::ceil<__dur>(__rtime), 
178 std::move(__p)); 
179
180 
181 native_handle_type 
182 native_handle() 
183 { return _M_cond.native_handle(); } 
184 
185 private
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 .tv_sec: static_cast<std::time_t>(__s.time_since_epoch().count()), 
198 .tv_nsec: static_cast<long>(__ns.count()) 
199 }; 
200 
201 _M_cond.wait_until(m&: *__lock.mutex(), CLOCK_MONOTONIC, abs_time&: __ts); 
202 
203 return (steady_clock::now() < __atime 
204 ? cv_status::no_timeout : cv_status::timeout); 
205
206#endif 
207 
208 template<typename _Dur> 
209 cv_status 
210 __wait_until_impl(unique_lock<mutex>& __lock
211 const chrono::time_point<system_clock, _Dur>& __atime
212
213 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 
214 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 
215 
216 __gthread_time_t __ts
217
218 .tv_sec: static_cast<std::time_t>(__s.time_since_epoch().count()), 
219 .tv_nsec: static_cast<long>(__ns.count()) 
220 }; 
221 
222 _M_cond.wait_until(m&: *__lock.mutex(), abs_time&: __ts); 
223 
224 return (system_clock::now() < __atime 
225 ? cv_status::no_timeout : cv_status::timeout); 
226
227 }; 
228 
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 
238 inline namespace _V2
239 
240 /// condition_variable_any 
241 // Like above, but mutex is not required to have try_lock. 
242 class condition_variable_any 
243
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 
249 condition_variable _M_cond
250 shared_ptr<mutex> _M_mutex
251 
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 
258#pragma GCC diagnostic push 
259#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 
260 ~_Unlock() noexcept(false
261
262 if (uncaught_exception()) 
263
264 __try 
265 { _M_lock.lock(); } 
266 __catch(const __cxxabiv1::__forced_unwind&) 
267 { __throw_exception_again; } 
268 __catch(...) 
269 { } 
270
271 else 
272 _M_lock.lock(); 
273
274#pragma GCC diagnostic pop 
275 
276 _Unlock(const _Unlock&) = delete
277 _Unlock& operator=(const _Unlock&) = delete
278 
279 _Lock& _M_lock
280 }; 
281 
282 public
283 condition_variable_any() : _M_mutex(std::make_shared<mutex>()) { } 
284 ~condition_variable_any() = default
285 
286 condition_variable_any(const condition_variable_any&) = delete
287 condition_variable_any& operator=(const condition_variable_any&) = delete
288 
289 void 
290 notify_one() noexcept 
291
292 lock_guard<mutex> __lock(*_M_mutex); 
293 _M_cond.notify_one(); 
294
295 
296 void 
297 notify_all() noexcept 
298
299 lock_guard<mutex> __lock(*_M_mutex); 
300 _M_cond.notify_all(); 
301
302 
303 template<typename _Lock> 
304 void 
305 wait(_Lock& __lock
306
307 shared_ptr<mutex> __mutex = _M_mutex
308 unique_lock<mutex> __my_lock(*__mutex); 
309 _Unlock<_Lock> __unlock(__lock); 
310 // *__mutex must be unlocked before re-locking __lock so move 
311 // ownership of *__mutex lock to an object with shorter lifetime. 
312 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 
313 _M_cond.wait(lock&: __my_lock2); 
314
315 
316 
317 template<typename _Lock, typename _Predicate> 
318 void 
319 wait(_Lock& __lock, _Predicate __p
320
321 while (!__p()) 
322 wait(__lock); 
323
324 
325 template<typename _Lock, typename _Clock, typename _Duration> 
326 cv_status 
327 wait_until(_Lock& __lock
328 const chrono::time_point<_Clock, _Duration>& __atime
329
330 shared_ptr<mutex> __mutex = _M_mutex
331 unique_lock<mutex> __my_lock(*__mutex); 
332 _Unlock<_Lock> __unlock(__lock); 
333 // *__mutex must be unlocked before re-locking __lock so move 
334 // ownership of *__mutex lock to an object with shorter lifetime. 
335 unique_lock<mutex> __my_lock2(std::move(__my_lock)); 
336 return _M_cond.wait_until(__my_lock2, __atime); 
337
338 
339 template<typename _Lock, typename _Clock, 
340 typename _Duration, typename _Predicate> 
341 bool 
342 wait_until(_Lock& __lock
343 const chrono::time_point<_Clock, _Duration>& __atime
344 _Predicate __p
345
346 while (!__p()) 
347 if (wait_until(__lock, __atime) == cv_status::timeout
348 return __p(); 
349 return true
350
351 
352 template<typename _Lock, typename _Rep, typename _Period> 
353 cv_status 
354 wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __rtime
355 { return wait_until(__lock, __clock_t::now() + __rtime); } 
356 
357 template<typename _Lock, typename _Rep, 
358 typename _Period, typename _Predicate> 
359 bool 
360 wait_for(_Lock& __lock
361 const chrono::duration<_Rep, _Period>& __rtime, _Predicate __p
362 { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } 
363 
364#ifdef __cpp_lib_jthread 
365 template <class _Lock, class _Predicate> 
366 bool wait(_Lock& __lock
367 stop_token __stoken
368 _Predicate __p
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(lock&: __my_lock2); 
389
390 return true
391
392 
393 template <class _Lock, class _Clock, class _Duration, class _Predicate> 
394 bool wait_until(_Lock& __lock
395 stop_token __stoken
396 const chrono::time_point<_Clock, _Duration>& __abs_time
397 _Predicate __p
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> 
429 bool wait_for(_Lock& __lock
430 stop_token __stoken
431 const chrono::duration<_Rep, _Period>& __rel_time
432 _Predicate __p
433
434 auto __abst = std::chrono::steady_clock::now() + __rel_time
435 return wait_until(__lock
436 std::move(__stoken), 
437 __abst
438 std::move(__p)); 
439
440#endif 
441 }; 
442 
443 } // end inline namespace 
444 
445 /// @} group condition_variables 
446_GLIBCXX_END_NAMESPACE_VERSION 
447} // namespace 
448 
449#endif // _GLIBCXX_HAS_GTHREADS 
450#endif // C++11 
451#endif // _GLIBCXX_CONDITION_VARIABLE 
452