1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP_CONDITION_VARIABLE
11#define _LIBCPP_CONDITION_VARIABLE
12
13/*
14 condition_variable synopsis
15
16namespace std
17{
18
19enum class cv_status { no_timeout, timeout };
20
21class condition_variable
22{
23public:
24 condition_variable();
25 ~condition_variable();
26
27 condition_variable(const condition_variable&) = delete;
28 condition_variable& operator=(const condition_variable&) = delete;
29
30 void notify_one() noexcept;
31 void notify_all() noexcept;
32
33 void wait(unique_lock<mutex>& lock);
34 template <class Predicate>
35 void wait(unique_lock<mutex>& lock, Predicate pred);
36
37 template <class Clock, class Duration>
38 cv_status
39 wait_until(unique_lock<mutex>& lock,
40 const chrono::time_point<Clock, Duration>& abs_time);
41
42 template <class Clock, class Duration, class Predicate>
43 bool
44 wait_until(unique_lock<mutex>& lock,
45 const chrono::time_point<Clock, Duration>& abs_time,
46 Predicate pred);
47
48 template <class Rep, class Period>
49 cv_status
50 wait_for(unique_lock<mutex>& lock,
51 const chrono::duration<Rep, Period>& rel_time);
52
53 template <class Rep, class Period, class Predicate>
54 bool
55 wait_for(unique_lock<mutex>& lock,
56 const chrono::duration<Rep, Period>& rel_time,
57 Predicate pred);
58
59 typedef pthread_cond_t* native_handle_type;
60 native_handle_type native_handle();
61};
62
63void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
64
65class condition_variable_any
66{
67public:
68 condition_variable_any();
69 ~condition_variable_any();
70
71 condition_variable_any(const condition_variable_any&) = delete;
72 condition_variable_any& operator=(const condition_variable_any&) = delete;
73
74 void notify_one() noexcept;
75 void notify_all() noexcept;
76
77 template <class Lock>
78 void wait(Lock& lock);
79 template <class Lock, class Predicate>
80 void wait(Lock& lock, Predicate pred);
81
82 template <class Lock, class Clock, class Duration>
83 cv_status
84 wait_until(Lock& lock,
85 const chrono::time_point<Clock, Duration>& abs_time);
86
87 template <class Lock, class Clock, class Duration, class Predicate>
88 bool
89 wait_until(Lock& lock,
90 const chrono::time_point<Clock, Duration>& abs_time,
91 Predicate pred);
92
93 template <class Lock, class Rep, class Period>
94 cv_status
95 wait_for(Lock& lock,
96 const chrono::duration<Rep, Period>& rel_time);
97
98 template <class Lock, class Rep, class Period, class Predicate>
99 bool
100 wait_for(Lock& lock,
101 const chrono::duration<Rep, Period>& rel_time,
102 Predicate pred);
103
104 // [thread.condvarany.intwait], interruptible waits
105 template <class Lock, class Predicate>
106 bool wait(Lock& lock, stop_token stoken, Predicate pred); // since C++20
107
108 template <class Lock, class Clock, class Duration, class Predicate>
109 bool wait_until(Lock& lock, stop_token stoken,
110 const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); // since C++20
111
112 template <class Lock, class Rep, class Period, class Predicate>
113 bool wait_for(Lock& lock, stop_token stoken,
114 const chrono::duration<Rep, Period>& rel_time, Predicate pred); // since C++20
115};
116
117} // std
118
119*/
120
121#include <__chrono/duration.h>
122#include <__chrono/steady_clock.h>
123#include <__chrono/time_point.h>
124#include <__condition_variable/condition_variable.h>
125#include <__config>
126#include <__memory/shared_ptr.h>
127#include <__mutex/lock_guard.h>
128#include <__mutex/mutex.h>
129#include <__mutex/tag_types.h>
130#include <__mutex/unique_lock.h>
131#include <__stop_token/stop_callback.h>
132#include <__stop_token/stop_token.h>
133#include <__utility/move.h>
134#include <version>
135
136#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
137# pragma GCC system_header
138#endif
139
140_LIBCPP_PUSH_MACROS
141#include <__undef_macros>
142
143#ifndef _LIBCPP_HAS_NO_THREADS
144
145_LIBCPP_BEGIN_NAMESPACE_STD
146
147class _LIBCPP_EXPORTED_FROM_ABI condition_variable_any {
148 condition_variable __cv_;
149 shared_ptr<mutex> __mut_;
150
151public:
152 _LIBCPP_HIDE_FROM_ABI condition_variable_any();
153
154 _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT;
155 _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT;
156
157 template <class _Lock>
158 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(_Lock& __lock);
159 template <class _Lock, class _Predicate>
160 _LIBCPP_HIDE_FROM_ABI void wait(_Lock& __lock, _Predicate __pred);
161
162 template <class _Lock, class _Clock, class _Duration>
163 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
164 wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t);
165
166 template <class _Lock, class _Clock, class _Duration, class _Predicate>
167 bool _LIBCPP_HIDE_FROM_ABI
168 wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
169
170 template <class _Lock, class _Rep, class _Period>
171 cv_status _LIBCPP_HIDE_FROM_ABI wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d);
172
173 template <class _Lock, class _Rep, class _Period, class _Predicate>
174 bool _LIBCPP_HIDE_FROM_ABI wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
175
176# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
177
178 template <class _Lock, class _Predicate>
179 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool wait(_Lock& __lock, stop_token __stoken, _Predicate __pred);
180
181 template <class _Lock, class _Clock, class _Duration, class _Predicate>
182 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool wait_until(
183 _Lock& __lock, stop_token __stoken, const chrono::time_point<_Clock, _Duration>& __abs_time, _Predicate __pred);
184
185 template <class _Lock, class _Rep, class _Period, class _Predicate>
186 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
187 wait_for(_Lock& __lock, stop_token __stoken, const chrono::duration<_Rep, _Period>& __rel_time, _Predicate __pred);
188
189# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
190};
191
192inline condition_variable_any::condition_variable_any() : __mut_(make_shared<mutex>()) {}
193
194inline void condition_variable_any::notify_one() _NOEXCEPT {
195 { lock_guard<mutex> __lx(*__mut_); }
196 __cv_.notify_one();
197}
198
199inline void condition_variable_any::notify_all() _NOEXCEPT {
200 { lock_guard<mutex> __lx(*__mut_); }
201 __cv_.notify_all();
202}
203
204template <class _Lock>
205struct __unlock_guard {
206 _Lock& __lock_;
207
208 _LIBCPP_HIDE_FROM_ABI __unlock_guard(_Lock& __lock) : __lock_(__lock) { __lock_.unlock(); }
209
210 _LIBCPP_HIDE_FROM_ABI ~__unlock_guard() _NOEXCEPT // turns exception to std::terminate
211 {
212 __lock_.lock();
213 }
214
215 __unlock_guard(const __unlock_guard&) = delete;
216 __unlock_guard& operator=(const __unlock_guard&) = delete;
217};
218
219template <class _Lock>
220void condition_variable_any::wait(_Lock& __lock) {
221 shared_ptr<mutex> __mut = __mut_;
222 unique_lock<mutex> __lk(*__mut);
223 __unlock_guard<_Lock> __unlock(__lock);
224 lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock_t());
225 __cv_.wait(__lk);
226} // __mut_.unlock(), __lock.lock()
227
228template <class _Lock, class _Predicate>
229inline void condition_variable_any::wait(_Lock& __lock, _Predicate __pred) {
230 while (!__pred())
231 wait(__lock);
232}
233
234template <class _Lock, class _Clock, class _Duration>
235cv_status condition_variable_any::wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t) {
236 shared_ptr<mutex> __mut = __mut_;
237 unique_lock<mutex> __lk(*__mut);
238 __unlock_guard<_Lock> __unlock(__lock);
239 lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock_t());
240 return __cv_.wait_until(__lk, __t);
241} // __mut_.unlock(), __lock.lock()
242
243template <class _Lock, class _Clock, class _Duration, class _Predicate>
244inline bool
245condition_variable_any::wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
246 while (!__pred())
247 if (wait_until(__lock, __t) == cv_status::timeout)
248 return __pred();
249 return true;
250}
251
252template <class _Lock, class _Rep, class _Period>
253inline cv_status condition_variable_any::wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d) {
254 return wait_until(__lock, chrono::steady_clock::now() + __d);
255}
256
257template <class _Lock, class _Rep, class _Period, class _Predicate>
258inline bool
259condition_variable_any::wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
260 return wait_until(__lock, chrono::steady_clock::now() + __d, std::move(__pred));
261}
262
263# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
264
265template <class _Lock, class _Predicate>
266bool condition_variable_any::wait(_Lock& __user_lock, stop_token __stoken, _Predicate __pred) {
267 if (__stoken.stop_requested())
268 return __pred();
269
270 // Per https://eel.is/c++draft/thread.condition.condvarany#general-note-2,
271 // we do need to take a copy of the shared pointer __mut_
272 // This ensures that a thread can call the destructor immediately after calling
273 // notify_all, without waiting all the wait calls.
274 // A thread can also safely call the destructor immediately after calling
275 // request_stop, as the call to request_stop would evaluate the callback,
276 // which accesses the internal condition variable, immediately on the same thread.
277 // In this situation, it is OK even without copying a shared ownership the internal
278 // condition variable. However, this needs the evaluation of stop_callback to
279 // happen-before the destruction.
280 // The spec only says "Only the notification to unblock the wait needs to happen
281 // before destruction". To make this work, we need to copy the shared ownership of
282 // the internal condition variable inside this function, which is not possible
283 // with the current ABI.
284 shared_ptr<mutex> __mut = __mut_;
285
286 stop_callback __cb(__stoken, [this] { notify_all(); });
287
288 while (true) {
289 if (__pred())
290 return true;
291
292 // We need to take the internal lock before checking stop_requested,
293 // so that the notification cannot come in between the stop_requested
294 // check and entering the wait.
295 // Note that the stop_callback takes the same internal lock before notifying
296 unique_lock<mutex> __internal_lock(*__mut);
297 if (__stoken.stop_requested())
298 break;
299
300 __unlock_guard<_Lock> __unlock(__user_lock);
301 unique_lock<mutex> __internal_lock2(
302 std::move(__internal_lock)); // switch unlock order between __internal_lock and __user_lock
303 __cv_.wait(__internal_lock2);
304 } // __internal_lock2.unlock(), __user_lock.lock()
305 return __pred();
306}
307
308template <class _Lock, class _Clock, class _Duration, class _Predicate>
309bool condition_variable_any::wait_until(
310 _Lock& __user_lock,
311 stop_token __stoken,
312 const chrono::time_point<_Clock, _Duration>& __abs_time,
313 _Predicate __pred) {
314 if (__stoken.stop_requested())
315 return __pred();
316
317 shared_ptr<mutex> __mut = __mut_;
318 stop_callback __cb(__stoken, [this] { notify_all(); });
319
320 while (true) {
321 if (__pred())
322 return true;
323
324 unique_lock<mutex> __internal_lock(*__mut);
325 if (__stoken.stop_requested())
326 break;
327
328 __unlock_guard<_Lock> __unlock(__user_lock);
329 unique_lock<mutex> __internal_lock2(
330 std::move(__internal_lock)); // switch unlock order between __internal_lock and __user_lock
331
332 if (__cv_.wait_until(__internal_lock2, __abs_time) == cv_status::timeout)
333 break;
334 } // __internal_lock2.unlock(), __user_lock.lock()
335 return __pred();
336}
337
338template <class _Lock, class _Rep, class _Period, class _Predicate>
339bool condition_variable_any::wait_for(
340 _Lock& __lock, stop_token __stoken, const chrono::duration<_Rep, _Period>& __rel_time, _Predicate __pred) {
341 return wait_until(__lock, std::move(__stoken), chrono::steady_clock::now() + __rel_time, std::move(__pred));
342}
343
344# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
345
346_LIBCPP_EXPORTED_FROM_ABI void notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
347
348_LIBCPP_END_NAMESPACE_STD
349
350#endif // !_LIBCPP_HAS_NO_THREADS
351
352_LIBCPP_POP_MACROS
353
354#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
355# include <atomic>
356# include <concepts>
357# include <cstdint>
358# include <cstdlib>
359# include <cstring>
360# include <initializer_list>
361# include <iosfwd>
362# include <new>
363# include <stdexcept>
364# include <system_error>
365# include <type_traits>
366# include <typeinfo>
367#endif
368
369#endif // _LIBCPP_CONDITION_VARIABLE
370