µ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 Liviu Ionescu.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28/*
29 * The code is inspired by LLVM libcxx and GNU libstdc++-v3.
30 */
31
32#ifndef CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
33#define CMSIS_PLUS_ESTD_CONDITION_VARIABLE_
34
35// ----------------------------------------------------------------------------
36
37// Include the next <condition_variable> file found in the search path.
38#pragma GCC diagnostic push
39#if defined(__clang__)
40#pragma clang diagnostic ignored "-Wgnu-include-next"
41#endif
42#include_next <condition_variable>
43#pragma GCC diagnostic pop
44
45#include <memory>
46#include <chrono>
47
48#include <cmsis-plus/estd/mutex>
49
50// ----------------------------------------------------------------------------
51
52#pragma GCC diagnostic push
53
54#if defined(__clang__)
55#pragma clang diagnostic ignored "-Wc++98-compat"
56#endif
57
58// ----------------------------------------------------------------------------
59
60namespace os
61{
62 namespace estd
63 {
64
70 // ========================================================================
87 enum class cv_status
88 {
89 no_timeout, //
91 };
92
94 {
95 private:
96
98
99 public:
100
102
104
106
110
111 void
112 notify_one () noexcept;
113
114 void
115 notify_all () noexcept;
116
117 void
118 wait (std::unique_lock<mutex>& lock);
119
120 template<class Predicate_T>
121 void
122 wait (std::unique_lock<mutex>& lock, Predicate_T pred);
123
124 template<class Clock_T, class Duration_T>
126 wait_until (
127 std::unique_lock<mutex>& lock,
128 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
129
130 template<class Clock_T, class Duration_T, class Predicate_T>
131 bool
132 wait_until (
133 std::unique_lock<mutex>& lock,
134 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
135 Predicate_T pred);
136
137 template<class Rep_T, class Period_T>
139 wait_for (std::unique_lock<mutex>& lock,
140 const std::chrono::duration<Rep_T, Period_T>& rel_time);
141
142 template<class Rep_T, class Period_T, class Predicate_T>
143 bool
144 wait_for (std::unique_lock<mutex>& lock,
145 const std::chrono::duration<Rep_T, Period_T>& rel_time,
146 Predicate_T pred);
147
150
151 protected:
152
154 using Native_clock = os::estd::chrono::systick_clock;
155
156 };
157
158 void
160 std::unique_lock<mutex> lk);
161
163 {
164 public:
165
167
169
173
174 void
175 notify_one () noexcept;
176
177 void
178 notify_all () noexcept;
179
180 template<class Lock_T>
181 void
182 wait (Lock_T& lock);
183
184 template<class Lock_T, class Predicate_T>
185 void
186 wait (Lock_T& lock, Predicate_T pred);
187
188 template<class Lock_T, class Clock_T, class Duration_T>
190 wait_until (
191 Lock_T& lock,
192 const std::chrono::time_point<Clock_T, Duration_T>& abs_time);
193
194 template<class Lock_T, class Clock_T, class Duration_T, class Predicate_T>
195 bool
196 wait_until (
197 Lock_T& lock,
198 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
199 Predicate_T pred);
200
201 template<class Lock_T, class Rep_T, class Period_T>
203 wait_for (Lock_T& lock,
204 const std::chrono::duration<Rep_T, Period_T>& rel_time);
205
206 template<class Lock_T, class Rep_T, class Period_T, class Predicate_T>
207 bool
208 wait_for (Lock_T& lock,
209 const std::chrono::duration<Rep_T, Period_T>& rel_time,
210 Predicate_T pred);
211
212 protected:
213
215 std::shared_ptr<mutex> mx_;
216
217 using Native_clock = os::estd::chrono::systick_clock;
218
219 };
220
225 // ========================================================================
226 // Inline & template implementations.
227 // ========================================================================
228 inline
230 {
231 ;
232 }
233
234 inline
236 {
237 ;
238 }
239
240 template<class Predicate_T>
241 void
242 condition_variable::wait (std::unique_lock<mutex>& lock, Predicate_T pred)
243 {
244 while (!pred ())
245 wait (lock);
246 }
247
248#pragma GCC diagnostic push
249#pragma GCC diagnostic ignored "-Waggregate-return"
250
251 template<class Clock_T, class Duration_T>
254 std::unique_lock<mutex>& lock,
255 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
256 {
257 using namespace std::chrono;
258 using clock = Clock_T;
259
260#if 0
261 wait_for (lock, abs_time - Clock_T::now ());
262 return
263 Clock_T::now () < abs_time ?
265#else
266 // Optimise to native (ticks). LLVM compares using the
267 // original clock, which might be more accurate.
268 Native_clock::duration rel_time = std::chrono::duration_cast<
269 Native_clock::duration> (abs_time - clock::now ());
270 return wait_for (lock, rel_time);
271#endif
272 }
273
274#pragma GCC diagnostic pop
275
276 template<class Clock_T, class Duration_T, class Predicate_T>
277 bool
279 std::unique_lock<mutex>& lock,
280 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
281 Predicate_T pred)
282 {
283 while (!pred ())
284 {
285 if (wait_until (lock, abs_time) == cv_status::timeout)
286 return pred ();
287 }
288 return true;
289 }
290
291#pragma GCC diagnostic push
292#pragma GCC diagnostic ignored "-Waggregate-return"
293
294 template<class Rep_T, class Period_T>
297 std::unique_lock<mutex>& lock,
298 const std::chrono::duration<Rep_T, Period_T>& rel_time)
299 {
300 using namespace std::chrono;
301
302 if (rel_time <= rel_time.zero ())
303 {
304 return cv_status::timeout;
305 }
306
308
310 std::chrono::duration<os::rtos::clock::duration_t,
311 typename Native_clock::period>> (rel_time).count ();
312
314 /*(rtos::mutex &)*/(*(lock.mutex ()->native_handle ())),
315 ticks);
316
317 return
318 (Native_clock::now () - start_tp) < rel_time ?
320 }
321
322 template<class Rep_T, class Period_T, class Predicate_T>
323 inline
324 bool
326 std::unique_lock<mutex>& lock,
327 const std::chrono::duration<Rep_T, Period_T>& rel_time,
328 Predicate_T pred)
329 {
330 return wait_until (lock, Native_clock::now () + rel_time,
331 std::move (pred));
332 }
333
334#pragma GCC diagnostic pop
335
336 // ========================================================================
337
338 inline
340 cv_
341 { }, //
342 mx_
343 { std::make_shared<mutex> () }
344 {
345 ;
346 }
347
348 inline
350 {
351 ;
352 }
353
354 inline void
356 {
357 std::lock_guard<mutex> lock (*mx_);
358 cv_.notify_one ();
359 }
360
361 inline void
363 {
364 std::lock_guard<mutex> lock (*mx_);
365 cv_.notify_all ();
366 }
367
369 {
370 template<class Lock_T>
371 void
372 operator() (Lock_T* lk)
373 {
374 lk->lock ();
375 }
376 };
377
378 template<class Lock_T>
379 void
381 {
382 std::shared_ptr<mutex> mx = mx_;
383 std::unique_lock<mutex> lk (*mx);
384 lock.unlock ();
385 std::unique_ptr<Lock_T, __lock_external> lxx(&lock);
386 std::lock_guard<std::unique_lock<mutex> > lx (lk, std::adopt_lock);
387
388 cv_.wait (lk);
389 // mx.unlock()
390 // lock.lock()
391 }
392
393 template<class Lock_T, class Predicate_T>
394 inline void
395 condition_variable_any::wait (Lock_T& lock, Predicate_T pred)
396 {
397 while (!pred ())
398 wait (lock);
399 }
400
401 template<class Lock_T, class Clock_T, class Duration_T>
404 Lock_T& lock,
405 const std::chrono::time_point<Clock_T, Duration_T>& abs_time)
406 {
407 std::shared_ptr<mutex> mx = mx_;
408 std::unique_lock<mutex> lk (*mx);
409 lock.unlock ();
410 std::unique_ptr<Lock_T, __lock_external> lxx(&lock);
411 std::lock_guard<std::unique_lock<mutex> > lx (lk, std::adopt_lock);
412
413 return cv_.wait_until (lk, abs_time);
414 // mx.unlock()
415 // lock.lock()
416 }
417
418 template<class Lock_T, class Clock_T, class Duration_T, class Predicate_T>
419 inline bool
421 Lock_T& lock,
422 const std::chrono::time_point<Clock_T, Duration_T>& abs_time,
423 Predicate_T pred)
424 {
425 while (!pred ())
426 {
427 if (wait_until (lock, abs_time) == cv_status::timeout)
428 {
429 return pred ();
430 }
431 }
432 return true;
433
434 }
435
436 template<class Lock_T, class Rep_T, class Period_T>
437 inline cv_status
439 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time)
440 {
441 return wait_until (lock, Native_clock::now () + rel_time);
442 }
443
444 template<class Lock_T, class Rep_T, class Period_T, class Predicate_T>
445 inline bool
447 Lock_T& lock, const std::chrono::duration<Rep_T, Period_T>& rel_time,
448 Predicate_T pred)
449 {
450 return wait_until (lock, Native_clock::now () + rel_time,
451 std::move (pred));
452 }
453
454 // ==========================================================================
455 } /* namespace estd */
456} /* namespace os */
457
458#pragma GCC diagnostic pop
459
460#if defined(OS_HAS_STD_THREADS)
461
462namespace std
463{
469 // Redefine the objects in the std:: namespace.
470
471 using cv_status = os::estd::cv_status;
472
473 using condition_variable = os::estd::condition_variable;
474 using condition_variable_any = os::estd::condition_variable_any;
475
479}
480
481#endif
482
483// ----------------------------------------------------------------------------
484
485#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:91
std::chrono::time_point< systick_clock > time_point
basic time_point type of clock
Definition chrono:96
static time_point now() noexcept
Definition chrono.cpp:61
std::chrono::duration< rep, period > duration
basic duration type of clock
Definition chrono:93
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:62
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:83
constexpr std::enable_if< std::chrono::__is_duration< _To >::value, _To >::type ceil(std::chrono::duration< Rep_T, Period_T > d)
Definition chrono:278
System namespace.
Standard std namespace.