µ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++ distribution.
3 * (https://github.com/micro-os-plus)
4 * Copyright (c) 2016-2023 Liviu Ionescu. All rights reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from https://opensource.org/licenses/mit/.
11 */
12
13/*
14 * The code is inspired by LLVM libcxx and GNU libstdc++-v3.
15 */
16
17#ifndef CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
18#define CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
19
20// ----------------------------------------------------------------------------
21
22// Include the next <condition_variable> file found in the search path.
23#pragma GCC diagnostic push
24#if defined(__clang__)
25#pragma clang diagnostic ignored "-Wgnu-include-next"
26#endif
27#include_next <condition_variable>
28#pragma GCC diagnostic pop
29
30#include <memory>
31#include <chrono>
32
33#include <cmsis-plus/estd/mutex>
34
35// ----------------------------------------------------------------------------
36
37#pragma GCC diagnostic push
38#if defined(__clang__)
39#pragma clang diagnostic ignored "-Wc++98-compat"
40#endif
41
42// ----------------------------------------------------------------------------
43
44namespace os
45{
46 namespace estd
47 {
48
54 // ========================================================================
71 enum class cv_status
72 {
73 no_timeout, //
75 };
76
78 {
79 private:
80
82
83 public:
84
86
88
90
94
95 void
96 notify_one () noexcept;
97
98 void
99 notify_all () noexcept;
100
101 void
102 wait (std::unique_lock<mutex>& lock);
103
104 template<class Predicate_T>
105 void
106 wait (std::unique_lock<mutex>& lock, Predicate_T pred);
107
108 template<class Clock_T, class Duration_T>
110 wait_until (
111 std::unique_lock<mutex>& lock,
112 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
113
114 template<class Clock_T, class Duration_T, class Predicate_T>
115 bool
116 wait_until (
117 std::unique_lock<mutex>& lock,
118 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
119 Predicate_T pred);
120
121 template<class Rep_T, class Period_T>
123 wait_for (std::unique_lock<mutex>& lock,
124 const std::chrono::duration<Rep_T, Period_T>& rel_time);
125
126 template<class Rep_T, class Period_T, class Predicate_T>
127 bool
128 wait_for (std::unique_lock<mutex>& lock,
129 const std::chrono::duration<Rep_T, Period_T>& rel_time,
130 Predicate_T pred);
131
134
135 protected:
136
138 using Native_clock = os::estd::chrono::systick_clock;
139
140 };
141
142 void
144 std::unique_lock<mutex> lk);
145
147 {
148 public:
149
151
153
157
158 void
159 notify_one () noexcept;
160
161 void
162 notify_all () noexcept;
163
164 template<class Lock_T>
165 void
166 wait (Lock_T& lock);
167
168 template<class Lock_T, class Predicate_T>
169 void
170 wait (Lock_T& lock, Predicate_T pred);
171
172 template<class Lock_T, class Clock_T, class Duration_T>
174 wait_until (
175 Lock_T& lock,
176 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
177
178 template<class Lock_T, class Clock_T, class Duration_T, class Predicate_T>
179 bool
180 wait_until (
181 Lock_T& lock,
182 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
183 Predicate_T pred);
184
185 template<class Lock_T, class Rep_T, class Period_T>
187 wait_for (Lock_T& lock,
188 const std::chrono::duration<Rep_T, Period_T>& rel_time);
189
190 template<class Lock_T, class Rep_T, class Period_T, class Predicate_T>
191 bool
192 wait_for (Lock_T& lock,
193 const std::chrono::duration<Rep_T, Period_T>& rel_time,
194 Predicate_T pred);
195
196 protected:
197
199 std::shared_ptr<mutex> mx_;
200
201 using Native_clock = os::estd::chrono::systick_clock;
202
203 };
204
209 // ========================================================================
210 // Inline & template implementations.
211 // ========================================================================
212 inline
214 {
215 }
216
217 inline
219 {
220 }
221
222 template<class Predicate_T>
223 void
224 condition_variable::wait (std::unique_lock<mutex>& lock, Predicate_T pred)
225 {
226 while (!pred ())
227 wait (lock);
228 }
229
230#pragma GCC diagnostic push
231#if defined(__clang__)
232#elif defined(__GNUC__)
233#pragma GCC diagnostic ignored "-Waggregate-return"
234#endif
235
236 template<class Clock_T, class Duration_T>
239 std::unique_lock<mutex>& lock,
240 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
241 {
242 using namespace std::chrono;
243 using clock = Clock_T;
244
245#if 0
246 wait_for (lock, abs_time - Clock_T::now ());
247 return
248 Clock_T::now () < abs_time ?
250#else
251 // Optimise to native (ticks). LLVM compares using the
252 // original clock, which might be more accurate.
253 Native_clock::duration rel_time = std::chrono::duration_cast<
254 Native_clock::duration> (abs_time - clock::now ());
255 return wait_for (lock, rel_time);
256#endif
257 }
258
259#pragma GCC diagnostic pop
260
261 template<class Clock_T, class Duration_T, class Predicate_T>
262 bool
264 std::unique_lock<mutex>& lock,
265 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
266 Predicate_T pred)
267 {
268 while (!pred ())
269 {
270 if (wait_until (lock, abs_time) == cv_status::timeout)
271 return pred ();
272 }
273 return true;
274 }
275
276#pragma GCC diagnostic push
277#if defined(__clang__)
278#elif defined(__GNUC__)
279#pragma GCC diagnostic ignored "-Waggregate-return"
280#endif
281
282 template<class Rep_T, class Period_T>
285 std::unique_lock<mutex>& lock,
286 const std::chrono::duration<Rep_T, Period_T>& rel_time)
287 {
288 using namespace std::chrono;
289
290 if (rel_time <= rel_time.zero ())
291 {
292 return cv_status::timeout;
293 }
294
296
298 std::chrono::duration<os::rtos::clock::duration_t,
299 typename Native_clock::period>> (rel_time).count ();
300
302 /*(rtos::mutex &)*/(*(lock.mutex ()->native_handle ())),
303 ticks);
304
305 return
306 (Native_clock::now () - start_tp) < rel_time ?
308 }
309
310 template<class Rep_T, class Period_T, class Predicate_T>
311 inline
312 bool
314 std::unique_lock<mutex>& lock,
315 const std::chrono::duration<Rep_T, Period_T>& rel_time,
316 Predicate_T pred)
317 {
318 return wait_until (lock, Native_clock::now () + rel_time,
319 std::move (pred));
320 }
321
322#pragma GCC diagnostic pop
323
324 // ========================================================================
325
326 inline
328 cv_
329 { }, //
330 mx_
331 { std::make_shared<mutex> () }
332 {
333 }
334
335 inline
337 {
338 }
339
340 inline void
342 {
343 std::lock_guard<mutex> lock (*mx_);
344 cv_.notify_one ();
345 }
346
347 inline void
349 {
350 std::lock_guard<mutex> lock (*mx_);
351 cv_.notify_all ();
352 }
353
354#pragma GCC diagnostic push
355#if defined(__clang__)
356#pragma clang diagnostic ignored "-Wreserved-identifier"
357#endif
359 {
360 template<class Lock_T>
361 void
362 operator() (Lock_T* lk)
363 {
364 lk->lock ();
365 }
366 };
367#pragma GCC diagnostic pop
368
369 template<class Lock_T>
370 void
372 {
373 std::shared_ptr<mutex> mx = mx_;
374 std::unique_lock<mutex> lk (*mx);
375 lock.unlock ();
376 std::unique_ptr<Lock_T, __lock_external> lxx(&lock);
377 std::lock_guard<std::unique_lock<mutex> > lx (lk, std::adopt_lock);
378
379 cv_.wait (lk);
380 // mx.unlock()
381 // lock.lock()
382 }
383
384 template<class Lock_T, class Predicate_T>
385 inline void
386 condition_variable_any::wait (Lock_T& lock, Predicate_T pred)
387 {
388 while (!pred ())
389 wait (lock);
390 }
391
392 template<class Lock_T, class Clock_T, class Duration_T>
395 Lock_T& lock,
396 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
397 {
398 std::shared_ptr<mutex> mx = mx_;
399 std::unique_lock<mutex> lk (*mx);
400 lock.unlock ();
401 std::unique_ptr<Lock_T, __lock_external> lxx(&lock);
402 std::lock_guard<std::unique_lock<mutex> > lx (lk, std::adopt_lock);
403
404 return cv_.wait_until (lk, abs_time);
405 // mx.unlock()
406 // lock.lock()
407 }
408
409 template<class Lock_T, class Clock_T, class Duration_T, class Predicate_T>
410 inline bool
412 Lock_T& lock,
413 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
414 Predicate_T pred)
415 {
416 while (!pred ())
417 {
418 if (wait_until (lock, abs_time) == cv_status::timeout)
419 {
420 return pred ();
421 }
422 }
423 return true;
424
425 }
426
427 template<class Lock_T, class Rep_T, class Period_T>
428 inline cv_status
430 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time)
431 {
432 return wait_until (lock, Native_clock::now () + rel_time);
433 }
434
435 template<class Lock_T, class Rep_T, class Period_T, class Predicate_T>
436 inline bool
438 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time,
439 Predicate_T pred)
440 {
441 return wait_until (lock, Native_clock::now () + rel_time,
442 std::move (pred));
443 }
444
445 // ==========================================================================
446 } /* namespace estd */
447} /* namespace os */
448
449#pragma GCC diagnostic pop
450
451#if defined(OS_HAS_STD_THREADS)
452
453namespace std
454{
460 // Redefine the objects in the std:: namespace.
461
462 using cv_status = os::estd::cv_status;
463
464 using condition_variable = os::estd::condition_variable;
465 using condition_variable_any = os::estd::condition_variable_any;
466
470}
471
472#endif
473
474// ----------------------------------------------------------------------------
475
476#endif /* CMSIS_PLUS_ESTD_CONDITION_VARIABLE_ */
std::ratio< 1, os::rtos::clock_systick::frequency_hz > period
std::ratio type representing the tick period of the clock, in seconds
Definition chrono:75
std::chrono::time_point< systick_clock > time_point
basic time_point type of clock
Definition chrono:80
static time_point now() noexcept
Definition chrono.cpp:49
std::chrono::duration< rep, period > duration
basic duration type of clock
Definition chrono:77
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:46
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:76
constexpr std::enable_if< std::chrono::__is_duration< _To >::value, _To >::type ceil(std::chrono::duration< Rep_T, Period_T > d)
Definition chrono:269
System namespace.
Standard std namespace.