µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
condition_variable
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2016-2025 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software
6 * for any purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can
9 * be obtained from https://opensource.org/licenses/mit.
10 */
11
12/*
13 * The code is inspired by LLVM libcxx and GNU libstdc++-v3.
14 */
15
16#ifndef CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
17#define CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
18
19// ----------------------------------------------------------------------------
20
21// Include the next <condition_variable> file found in the search path.
22#pragma GCC diagnostic push
23#if defined(__clang__)
24#pragma clang diagnostic ignored "-Wgnu-include-next"
25#endif
26#include_next <condition_variable>
27#pragma GCC diagnostic pop
28
29#include <memory>
30#include <chrono>
31
32#include <cmsis-plus/estd/mutex>
33
34// ----------------------------------------------------------------------------
35
36#pragma GCC diagnostic push
37#if defined(__clang__)
38#pragma clang diagnostic ignored "-Wc++98-compat"
39#endif
40
41// ----------------------------------------------------------------------------
42
43namespace os
44{
45 namespace estd
46 {
47
53 // ========================================================================
70 enum class cv_status
71 {
72 no_timeout, //
74 };
75
77 {
78 private:
80
81 public:
83
85
87
91 = delete;
92
93 void
94 notify_one () noexcept;
95
96 void
97 notify_all () noexcept;
98
99 void
100 wait (std::unique_lock<mutex>& lock);
101
102 template <class Predicate_T>
103 void
104 wait (std::unique_lock<mutex>& lock, Predicate_T pred);
105
106 template <class Clock_T, class Duration_T>
108 wait_until (
109 std::unique_lock<mutex>& lock,
110 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
111
112 template <class Clock_T, class Duration_T, class Predicate_T>
113 bool
114 wait_until (std::unique_lock<mutex>& lock,
115 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
116 Predicate_T pred);
117
118 template <class Rep_T, class Period_T>
120 wait_for (std::unique_lock<mutex>& lock,
121 const std::chrono::duration<Rep_T, Period_T>& rel_time);
122
123 template <class Rep_T, class Period_T, class Predicate_T>
124 bool
125 wait_for (std::unique_lock<mutex>& lock,
126 const std::chrono::duration<Rep_T, Period_T>& rel_time,
127 Predicate_T pred);
128
131
132 protected:
134 using Native_clock = os::estd::chrono::systick_clock;
135 };
136
137 void
139 std::unique_lock<mutex> lk);
140
142 {
143 public:
145
147
151 = delete;
152
153 void
154 notify_one () noexcept;
155
156 void
157 notify_all () noexcept;
158
159 template <class Lock_T>
160 void
161 wait (Lock_T& lock);
162
163 template <class Lock_T, class Predicate_T>
164 void
165 wait (Lock_T& lock, Predicate_T pred);
166
167 template <class Lock_T, class Clock_T, class Duration_T>
169 wait_until (
170 Lock_T& lock,
171 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
172
173 template <class Lock_T, class Clock_T, class Duration_T,
174 class Predicate_T>
175 bool
176 wait_until (Lock_T& lock,
177 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
178 Predicate_T pred);
179
180 template <class Lock_T, class Rep_T, class Period_T>
182 wait_for (Lock_T& lock,
183 const std::chrono::duration<Rep_T, Period_T>& rel_time);
184
185 template <class Lock_T, class Rep_T, class Period_T, class Predicate_T>
186 bool
187 wait_for (Lock_T& lock,
188 const std::chrono::duration<Rep_T, Period_T>& rel_time,
189 Predicate_T pred);
190
191 protected:
193 std::shared_ptr<mutex> mx_;
194
195 using Native_clock = os::estd::chrono::systick_clock;
196 };
197
202 // ========================================================================
203 // Inline & template implementations.
204 // ========================================================================
206 {
207 }
208
210 {
211 }
212
213 template <class Predicate_T>
214 void
215 condition_variable::wait (std::unique_lock<mutex>& lock, Predicate_T pred)
216 {
217 while (!pred ())
218 wait (lock);
219 }
220
221#pragma GCC diagnostic push
222#if defined(__clang__)
223#elif defined(__GNUC__)
224#pragma GCC diagnostic ignored "-Waggregate-return"
225#endif
226
227 template <class Clock_T, class Duration_T>
230 std::unique_lock<mutex>& lock,
231 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
232 {
233 using namespace std::chrono;
234 using clock = Clock_T;
235
236#if 0
237 wait_for (lock, abs_time - Clock_T::now ());
238 return
239 Clock_T::now () < abs_time ?
241#else
242 // Optimise to native (ticks). LLVM compares using the
243 // original clock, which might be more accurate.
245 = std::chrono::duration_cast<Native_clock::duration> (
246 abs_time - clock::now ());
247 return wait_for (lock, rel_time);
248#endif
249 }
250
251#pragma GCC diagnostic pop
252
253 template <class Clock_T, class Duration_T, class Predicate_T>
254 bool
256 std::unique_lock<mutex>& lock,
257 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
258 Predicate_T pred)
259 {
260 while (!pred ())
261 {
262 if (wait_until (lock, abs_time) == cv_status::timeout)
263 return pred ();
264 }
265 return true;
266 }
267
268#pragma GCC diagnostic push
269#if defined(__clang__)
270#elif defined(__GNUC__)
271#pragma GCC diagnostic ignored "-Waggregate-return"
272#endif
273
274 template <class Rep_T, class Period_T>
277 std::unique_lock<mutex>& lock,
278 const std::chrono::duration<Rep_T, Period_T>& rel_time)
279 {
280 using namespace std::chrono;
281
282 if (rel_time <= rel_time.zero ())
283 {
284 return cv_status::timeout;
285 }
286
288
290 = os::estd::chrono::ceil<std::chrono::duration<
292 rel_time)
293 .count ();
294
296 /*(rtos::mutex &)*/ (*(lock.mutex ()->native_handle ())), ticks);
297
298 return (Native_clock::now () - start_tp) < rel_time
301 }
302
303 template <class Rep_T, class Period_T, class Predicate_T>
304 inline bool
306 std::unique_lock<mutex>& lock,
307 const std::chrono::duration<Rep_T, Period_T>& rel_time,
308 Predicate_T pred)
309 {
310 return wait_until (lock, Native_clock::now () + rel_time,
311 std::move (pred));
312 }
313
314#pragma GCC diagnostic pop
315
316 // ========================================================================
317
319 : cv_{}, //
320 mx_{ std::make_shared<mutex> () }
321 {
322 }
323
325 {
326 }
327
328 inline void
330 {
331 std::lock_guard<mutex> lock (*mx_);
332 cv_.notify_one ();
333 }
334
335 inline void
337 {
338 std::lock_guard<mutex> lock (*mx_);
339 cv_.notify_all ();
340 }
341
342#pragma GCC diagnostic push
343#if defined(__clang__)
344#pragma clang diagnostic ignored "-Wreserved-identifier"
345#endif
347 {
348 template <class Lock_T>
349 void
350 operator() (Lock_T* lk)
351 {
352 lk->lock ();
353 }
354 };
355#pragma GCC diagnostic pop
356
357 template <class Lock_T>
358 void
360 {
361 std::shared_ptr<mutex> mx = mx_;
362 std::unique_lock<mutex> lk (*mx);
363 lock.unlock ();
364 std::unique_ptr<Lock_T, __lock_external> lxx (&lock);
365 std::lock_guard<std::unique_lock<mutex>> lx (lk, std::adopt_lock);
366
367 cv_.wait (lk);
368 // mx.unlock()
369 // lock.lock()
370 }
371
372 template <class Lock_T, class Predicate_T>
373 inline void
374 condition_variable_any::wait (Lock_T& lock, Predicate_T pred)
375 {
376 while (!pred ())
377 wait (lock);
378 }
379
380 template <class Lock_T, class Clock_T, class Duration_T>
383 Lock_T& lock,
384 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
385 {
386 std::shared_ptr<mutex> mx = mx_;
387 std::unique_lock<mutex> lk (*mx);
388 lock.unlock ();
389 std::unique_ptr<Lock_T, __lock_external> lxx (&lock);
390 std::lock_guard<std::unique_lock<mutex>> lx (lk, std::adopt_lock);
391
392 return cv_.wait_until (lk, abs_time);
393 // mx.unlock()
394 // lock.lock()
395 }
396
397 template <class Lock_T, class Clock_T, class Duration_T, class Predicate_T>
398 inline bool
400 Lock_T& lock,
401 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
402 Predicate_T pred)
403 {
404 while (!pred ())
405 {
406 if (wait_until (lock, abs_time) == cv_status::timeout)
407 {
408 return pred ();
409 }
410 }
411 return true;
412 }
413
414 template <class Lock_T, class Rep_T, class Period_T>
415 inline cv_status
417 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time)
418 {
419 return wait_until (lock, Native_clock::now () + rel_time);
420 }
421
422 template <class Lock_T, class Rep_T, class Period_T, class Predicate_T>
423 inline bool
425 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time,
426 Predicate_T pred)
427 {
428 return wait_until (lock, Native_clock::now () + rel_time,
429 std::move (pred));
430 }
431
432 // ========================================================================
433 } /* namespace estd */
434} /* namespace os */
435
436#pragma GCC diagnostic pop
437
438#if defined(OS_HAS_STD_THREADS)
439
440namespace std
441{
447 // Redefine the objects in the std:: namespace.
448
449 using cv_status = os::estd::cv_status;
450
451 using condition_variable = os::estd::condition_variable;
452 using condition_variable_any = os::estd::condition_variable_any;
453
457} // namespace std
458
459#endif
460
461// ----------------------------------------------------------------------------
462
463#endif /* CMSIS_PLUS_ESTD_CONDITION_VARIABLE_ */
std::ratio< 1, os::rtos::clock_systick::frequency_hz > period
Definition chrono:74
std::chrono::time_point< systick_clock > time_point
basic time_point type of clock
Definition chrono:79
static time_point now() noexcept
Definition chrono.cpp:48
std::chrono::duration< rep, period > duration
basic duration type of clock
Definition chrono:76
condition_variable_any(const condition_variable_any &)=delete
cv_status wait_for(Lock_T &lock, const std::chrono::duration< Rep_T, Period_T > &rel_time)
cv_status wait_until(Lock_T &lock, const std::chrono::time_point< Clock_T, Duration_T > &abs_time)
condition_variable & operator=(const condition_variable &)=delete
void wait(std::unique_lock< mutex > &lock)
condition_variable(const condition_variable &)=delete
cv_status wait_until(std::unique_lock< mutex > &lock, const std::chrono::time_point< Clock_T, Duration_T > &abs_time)
native_handle_type native_handle()
cv_status wait_for(std::unique_lock< mutex > &lock, const std::chrono::duration< Rep_T, Period_T > &rel_time)
POSIX compliant condition variable.
Definition os-condvar.h:45
result_t timed_wait(mutex &mutex, clock::duration_t timeout)
Timed wait for a condition variable to be notified.
void notify_all_at_thread_exit(condition_variable &cond, std::unique_lock< mutex > lk)
clock_t clock(void)
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:78
constexpr std::enable_if< std::chrono::__is_duration< _To >::value, _To >::type ceil(std::chrono::duration< Rep_T, Period_T > d)
Definition chrono:258
System namespace.
Standard std namespace.