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#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
122# include <__cxx03/condition_variable>
123#else
124# include <__chrono/duration.h>
125# include <__chrono/steady_clock.h>
126# include <__chrono/time_point.h>
127# include <__condition_variable/condition_variable.h>
128# include <__config>
129# include <__memory/shared_ptr.h>
130# include <__mutex/lock_guard.h>
131# include <__mutex/mutex.h>
132# include <__mutex/tag_types.h>
133# include <__mutex/unique_lock.h>
134# include <__stop_token/stop_callback.h>
135# include <__stop_token/stop_token.h>
136# include <__utility/move.h>
137# include <version>
138
139# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
140# pragma GCC system_header
141# endif
142
143_LIBCPP_PUSH_MACROS
144# include <__undef_macros>
145
146# if _LIBCPP_HAS_THREADS
147
148_LIBCPP_BEGIN_NAMESPACE_STD
149_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
150
151template <class _Lock>
152struct __unlock_guard {
153 _Lock& __lock_;
154
155 _LIBCPP_HIDE_FROM_ABI __unlock_guard(_Lock& __lock) : __lock_(__lock) { __lock_.unlock(); }
156
157 _LIBCPP_HIDE_FROM_ABI ~__unlock_guard() _NOEXCEPT // turns exception to std::terminate
158 {
159 __lock_.lock();
160 }
161
162 __unlock_guard(const __unlock_guard&) = delete;
163 __unlock_guard& operator=(const __unlock_guard&) = delete;
164};
165
166class _LIBCPP_EXPORTED_FROM_ABI condition_variable_any {
167 condition_variable __cv_;
168 shared_ptr<mutex> __mut_;
169
170public:
171 _LIBCPP_HIDE_FROM_ABI condition_variable_any();
172
173 _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT;
174 _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT;
175
176 template <class _Lock>
177 _LIBCPP_HIDE_FROM_ABI void wait(_Lock& __lock) {
178 shared_ptr<mutex> __mut = __mut_;
179 unique_lock<mutex> __lk(*__mut);
180 __unlock_guard<_Lock> __unlock(__lock);
181 lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock_t());
182 __cv_.wait(__lk);
183 } // __mut_.unlock(), __lock.lock()
184
185 template <class _Lock, class _Predicate>
186 _LIBCPP_HIDE_FROM_ABI void wait(_Lock& __lock, _Predicate __pred);
187
188 template <class _Lock, class _Clock, class _Duration>
189 _LIBCPP_HIDE_FROM_ABI cv_status wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t) {
190 shared_ptr<mutex> __mut = __mut_;
191 unique_lock<mutex> __lk(*__mut);
192 __unlock_guard<_Lock> __unlock(__lock);
193 lock_guard<unique_lock<mutex> > __lx(__lk, adopt_lock_t());
194 return __cv_.wait_until(__lk, __t);
195 } // __mut_.unlock(), __lock.lock()
196
197 template <class _Lock, class _Clock, class _Duration, class _Predicate>
198 bool _LIBCPP_HIDE_FROM_ABI
199 wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
200
201 template <class _Lock, class _Rep, class _Period>
202 cv_status _LIBCPP_HIDE_FROM_ABI wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d);
203
204 template <class _Lock, class _Rep, class _Period, class _Predicate>
205 bool _LIBCPP_HIDE_FROM_ABI wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
206
207# if _LIBCPP_STD_VER >= 20
208
209 template <class _Lock, class _Predicate>
210 _LIBCPP_HIDE_FROM_ABI bool wait(_Lock& __lock, stop_token __stoken, _Predicate __pred);
211
212 template <class _Lock, class _Clock, class _Duration, class _Predicate>
213 _LIBCPP_HIDE_FROM_ABI bool wait_until(
214 _Lock& __lock, stop_token __stoken, const chrono::time_point<_Clock, _Duration>& __abs_time, _Predicate __pred);
215
216 template <class _Lock, class _Rep, class _Period, class _Predicate>
217 _LIBCPP_HIDE_FROM_ABI bool
218 wait_for(_Lock& __lock, stop_token __stoken, const chrono::duration<_Rep, _Period>& __rel_time, _Predicate __pred);
219
220# endif // _LIBCPP_STD_VER >= 20
221};
222
223inline condition_variable_any::condition_variable_any() : __mut_(make_shared<mutex>()) {}
224
225inline void condition_variable_any::notify_one() _NOEXCEPT {
226 { lock_guard<mutex> __lx(*__mut_); }
227 __cv_.notify_one();
228}
229
230inline void condition_variable_any::notify_all() _NOEXCEPT {
231 { lock_guard<mutex> __lx(*__mut_); }
232 __cv_.notify_all();
233}
234
235template <class _Lock, class _Predicate>
236inline void condition_variable_any::wait(_Lock& __lock, _Predicate __pred) {
237 while (!__pred())
238 wait(__lock);
239}
240
241template <class _Lock, class _Clock, class _Duration, class _Predicate>
242inline bool
243condition_variable_any::wait_until(_Lock& __lock, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
244 while (!__pred())
245 if (wait_until(__lock, __t) == cv_status::timeout)
246 return __pred();
247 return true;
248}
249
250template <class _Lock, class _Rep, class _Period>
251inline cv_status condition_variable_any::wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d) {
252 return wait_until(__lock, chrono::steady_clock::now() + __d);
253}
254
255template <class _Lock, class _Rep, class _Period, class _Predicate>
256inline bool
257condition_variable_any::wait_for(_Lock& __lock, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
258 return wait_until(__lock, chrono::steady_clock::now() + __d, std::move(__pred));
259}
260
261# if _LIBCPP_STD_VER >= 20
262
263template <class _Lock, class _Predicate>
264bool condition_variable_any::wait(_Lock& __user_lock, stop_token __stoken, _Predicate __pred) {
265 if (__stoken.stop_requested())
266 return __pred();
267
268 // Per https://eel.is/c++draft/thread.condition.condvarany#general-note-2,
269 // we do need to take a copy of the shared pointer __mut_
270 // This ensures that a thread can call the destructor immediately after calling
271 // notify_all, without waiting all the wait calls.
272 // A thread can also safely call the destructor immediately after calling
273 // request_stop, as the call to request_stop would evaluate the callback,
274 // which accesses the internal condition variable, immediately on the same thread.
275 // In this situation, it is OK even without copying a shared ownership the internal
276 // condition variable. However, this needs the evaluation of stop_callback to
277 // happen-before the destruction.
278 // The spec only says "Only the notification to unblock the wait needs to happen
279 // before destruction". To make this work, we need to copy the shared ownership of
280 // the internal condition variable inside this function, which is not possible
281 // with the current ABI.
282 shared_ptr<mutex> __mut = __mut_;
283
284 stop_callback __cb(__stoken, [this] { notify_all(); });
285
286 while (true) {
287 if (__pred())
288 return true;
289
290 // We need to take the internal lock before checking stop_requested,
291 // so that the notification cannot come in between the stop_requested
292 // check and entering the wait.
293 // Note that the stop_callback takes the same internal lock before notifying
294 unique_lock<mutex> __internal_lock(*__mut);
295 if (__stoken.stop_requested())
296 break;
297
298 __unlock_guard<_Lock> __unlock(__user_lock);
299 unique_lock<mutex> __internal_lock2(
300 std::move(__internal_lock)); // switch unlock order between __internal_lock and __user_lock
301 __cv_.wait(lk&: __internal_lock2);
302 } // __internal_lock2.unlock(), __user_lock.lock()
303 return __pred();
304}
305
306template <class _Lock, class _Clock, class _Duration, class _Predicate>
307bool condition_variable_any::wait_until(
308 _Lock& __user_lock,
309 stop_token __stoken,
310 const chrono::time_point<_Clock, _Duration>& __abs_time,
311 _Predicate __pred) {
312 if (__stoken.stop_requested())
313 return __pred();
314
315 shared_ptr<mutex> __mut = __mut_;
316 stop_callback __cb(__stoken, [this] { notify_all(); });
317
318 while (true) {
319 if (__pred())
320 return true;
321
322 unique_lock<mutex> __internal_lock(*__mut);
323 if (__stoken.stop_requested())
324 break;
325
326 __unlock_guard<_Lock> __unlock(__user_lock);
327 unique_lock<mutex> __internal_lock2(
328 std::move(__internal_lock)); // switch unlock order between __internal_lock and __user_lock
329
330 if (__cv_.wait_until(__internal_lock2, __abs_time) == cv_status::timeout)
331 break;
332 } // __internal_lock2.unlock(), __user_lock.lock()
333 return __pred();
334}
335
336template <class _Lock, class _Rep, class _Period, class _Predicate>
337bool condition_variable_any::wait_for(
338 _Lock& __lock, stop_token __stoken, const chrono::duration<_Rep, _Period>& __rel_time, _Predicate __pred) {
339 return wait_until(__lock, std::move(__stoken), chrono::steady_clock::now() + __rel_time, std::move(__pred));
340}
341
342# endif // _LIBCPP_STD_VER >= 20
343
344_LIBCPP_EXPORTED_FROM_ABI void notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>);
345
346_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
347_LIBCPP_END_NAMESPACE_STD
348
349# endif // _LIBCPP_HAS_THREADS
350
351_LIBCPP_POP_MACROS
352
353# if defined(_LIBCPP_KEEP_TRANSITIVE_INCLUDES_LLVM23) && _LIBCPP_STD_VER <= 23
354# include <atomic>
355# endif
356
357# if defined(_LIBCPP_KEEP_TRANSITIVE_INCLUDES_LLVM23) && _LIBCPP_STD_VER <= 20
358# include <concepts>
359# include <cstdint>
360# include <cstdlib>
361# include <cstring>
362# include <initializer_list>
363# include <iosfwd>
364# include <new>
365# include <optional>
366# include <stdexcept>
367# include <system_error>
368# include <type_traits>
369# include <typeinfo>
370# endif
371#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
372
373#endif // _LIBCPP_CONDITION_VARIABLE
374