µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
os-evflags.cpp
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#if defined(OS_USE_OS_APP_CONFIG_H)
14#include <cmsis-plus/os-app-config.h>
15#endif
16
17#include <cmsis-plus/rtos/os.h>
18
19// ----------------------------------------------------------------------------
20
21#if defined(__clang__)
22#pragma clang diagnostic ignored "-Wc++98-compat"
23#endif
24
25// ----------------------------------------------------------------------------
26
27namespace os
28{
29 namespace rtos
30 {
31 // ------------------------------------------------------------------------
32
51 const event_flags::attributes event_flags::initializer;
52
53 // ------------------------------------------------------------------------
54
128 { nullptr, attr }
129 {
130 }
131
132#pragma GCC diagnostic push
133#if defined(__clang__)
134#elif defined(__GNUC__)
135#pragma GCC diagnostic ignored "-Wunused-parameter"
136#endif
137
162 event_flags::event_flags (const char* name, const attributes& attr) :
163 object_named_system
164 { name }
165 {
166#if defined(OS_TRACE_RTOS_EVFLAGS)
167 trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
168#endif
169
170 // Don't call this from interrupt handlers.
172
173#if !defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
174 clock_ = attr.clock != nullptr ? attr.clock : &sysclock;
175#endif
176
177#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
178
179 port::event_flags::create (this);
180
181#else
182
183#endif
184
185 }
186
187#pragma GCC diagnostic pop
188
203 {
204#if defined(OS_TRACE_RTOS_EVFLAGS)
205 trace::printf ("%s() @%p %s\n", __func__, this, name ());
206#endif
207
208#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
209
210 port::event_flags::destroy (this);
211
212#else
213
214 // There must be no threads waiting for these flags.
215 assert(list_.empty ());
216
217#endif
218 }
219
243 flags::mode_t mode)
244 {
245#if defined(OS_TRACE_RTOS_EVFLAGS)
246 trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
247 name (), event_flags_.mask ());
248#endif
249
250 // Don't call this from interrupt handlers.
252 // Don't call this from critical regions.
254
255#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
256
257 return port::event_flags::wait (this, mask, oflags, mode);
258
259#else
260
261 {
262 // ----- Enter critical section -------------------------------------
264
265 if (event_flags_.check_raised (mask, oflags, mode))
266 {
267#if defined(OS_TRACE_RTOS_EVFLAGS)
268 trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
269 this, name (), event_flags_.mask ());
270#endif
271 return result::ok;
272 }
273 // ----- Exit critical section --------------------------------------
274 }
275
276 thread& crt_thread = this_thread::thread ();
277
278 // Prepare a list node pointing to the current thread.
279 // Do not worry for being on stack, it is temporarily linked to the
280 // list and guaranteed to be removed before this function returns.
282 { crt_thread };
283
284 for (;;)
285 {
286 {
287 // ----- Enter critical section ---------------------------------
289
290 if (event_flags_.check_raised (mask, oflags, mode))
291 {
292#if defined(OS_TRACE_RTOS_EVFLAGS)
293 trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask,
294 mode, this, name (), event_flags_.mask ());
295#endif
296 return result::ok;
297 }
298
299 // Add this thread to the event flags waiting list.
300 scheduler::internal_link_node (list_, node);
301 // state::suspended set in above link().
302 // ----- Exit critical section ----------------------------------
303 }
304
306
307 {
308 // ----- Enter critical section ---------------------------------
310
311 // Remove the thread from the event flags waiting list,
312 // if not already removed by raise().
313 scheduler::internal_unlink_node (node);
314 // ----- Exit critical section ----------------------------------
315 }
316
317 if (crt_thread.interrupted ())
318 {
319#if defined(OS_TRACE_RTOS_EVFLAGS)
320 trace::printf ("%s(0x%X,%u) EINTR @%p %s\n", __func__, mask, mode,
321 this, name ());
322#endif
323 return EINTR;
324 }
325 }
326
327 /* NOTREACHED */
328 return ENOTRECOVERABLE;
329
330#endif
331 }
332
346 flags::mode_t mode)
347 {
348#if defined(OS_TRACE_RTOS_EVFLAGS)
349 trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
350 name (), event_flags_.mask ());
351#endif
352
353#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
354
355 return port::event_flags::try_wait (this, mask, oflags, mode);
356
357#else
358
359 // Don't call this from high priority interrupts.
360 assert(port::interrupts::is_priority_valid ());
361
362 {
363 // ----- Enter critical section -------------------------------------
365
366 if (event_flags_.check_raised (mask, oflags, mode))
367 {
368#if defined(OS_TRACE_RTOS_EVFLAGS)
369 trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
370 this, name (), event_flags_.mask ());
371#endif
372 return result::ok;
373 }
374 else
375 {
376#if defined(OS_TRACE_RTOS_EVFLAGS)
377 trace::printf ("%s(0x%X,%u) EWOULDBLOCK @%p %s \n", __func__,
378 mask, mode, this, name ());
379#endif
380 return EWOULDBLOCK;
381 }
382 // ----- Exit critical section --------------------------------------
383 }
384
385#endif
386 }
387
428 flags::mask_t* oflags, flags::mode_t mode)
429 {
430#if defined(OS_TRACE_RTOS_EVFLAGS)
431 trace::printf ("%s(0x%X,%u,%u) @%p %s <0x%X\n", __func__, mask, timeout,
432 mode, this, name (), event_flags_.mask ());
433#endif
434
435 // Don't call this from interrupt handlers.
437 // Don't call this from critical regions.
439
440#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
441
442 return port::event_flags::timed_wait (this, mask, timeout, oflags, mode);
443
444#else
445
446 // Extra test before entering the loop, with its inherent weight.
447 // Trade size for speed.
448 {
449 // ----- Enter critical section -------------------------------------
451
452 if (event_flags_.check_raised (mask, oflags, mode))
453 {
454#if defined(OS_TRACE_RTOS_EVFLAGS)
455 trace::printf ("%s(0x%X,%u,%u) @%p %s >0x%X\n", __func__, mask,
456 timeout, mode, this, name (),
457 event_flags_.mask ());
458#endif
459 return result::ok;
460 }
461 // ----- Exit critical section --------------------------------------
462 }
463
464 thread& crt_thread = this_thread::thread ();
465
466 // Prepare a list node pointing to the current thread.
467 // Do not worry for being on stack, it is temporarily linked to the
468 // list and guaranteed to be removed before this function returns.
470 { crt_thread };
471
472 internal::clock_timestamps_list& clock_list = clock_->steady_list ();
473 clock::timestamp_t timeout_timestamp = clock_->steady_now () + timeout;
474
475 // Prepare a timeout node pointing to the current thread.
477 { timeout_timestamp, crt_thread };
478
479 for (;;)
480 {
481 {
482 // ----- Enter critical section ---------------------------------
484
485 if (event_flags_.check_raised (mask, oflags, mode))
486 {
487#if defined(OS_TRACE_RTOS_EVFLAGS)
488 trace::printf ("%s(0x%X,%u,%u) @%p %s >0x%X\n", __func__,
489 mask, timeout, mode, this, name (),
490 event_flags_.mask ());
491#endif
492 return result::ok;
493 }
494
495 // Add this thread to the event flags waiting list,
496 // and the clock timeout list.
497 scheduler::internal_link_node (list_, node, clock_list,
498 timeout_node);
499 // state::suspended set in above link().
500 // ----- Exit critical section ----------------------------------
501 }
502
504
505 // Remove the thread from the event flags waiting list,
506 // if not already removed by raise() and from the clock
507 // timeout list, if not already removed by the timer.
508 scheduler::internal_unlink_node (node, timeout_node);
509
510 if (crt_thread.interrupted ())
511 {
512#if defined(OS_TRACE_RTOS_EVFLAGS)
513 trace::printf ("%s(0x%X,%u,%u) EINTR @%p %s 0x%X \n", __func__,
514 mask, timeout, mode, this, name ());
515#endif
516 return EINTR;
517 }
518
519 if (clock_->steady_now () >= timeout_timestamp)
520 {
521#if defined(OS_TRACE_RTOS_EVFLAGS)
522 trace::printf ("%s(0x%X,%u,%u) ETIMEDOUT @%p %s 0x%X \n",
523 __func__, mask, timeout, mode, this, name ());
524#endif
525 return ETIMEDOUT;
526 }
527 }
528
529 /* NOTREACHED */
530 return ENOTRECOVERABLE;
531
532#endif
533 }
534
545 {
546#if defined(OS_TRACE_RTOS_EVFLAGS)
547 trace::printf ("%s(0x%X) @%p %s <0x%X \n", __func__, mask, this, name (),
548 event_flags_.mask ());
549#endif
550
551#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
552
553 os_assert_err(mask != 0, EINVAL);
554
555 return port::event_flags::raise (this, mask, oflags);
556
557#else
558
559 result_t res = event_flags_.raise (mask, oflags);
560
561 // Wake-up all threads, if any.
562 // Need not be inside the critical section,
563 // the list is protected by inner `resume_one()`.
564 list_.resume_all ();
565
566#if defined(OS_TRACE_RTOS_EVFLAGS)
567 trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
568 event_flags_.mask ());
569#endif
570 return res;
571
572#endif
573 }
574
580 {
581#if defined(OS_TRACE_RTOS_EVFLAGS)
582 trace::printf ("%s(0x%X) @%p %s <0x%X \n", __func__, mask, this, name (),
583 event_flags_.mask ());
584#endif
585
586#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
587
588 os_assert_err(mask != 0, EINVAL);
589
590 return port::event_flags::clear (this, mask, oflags);
591
592#else
593
594 result_t res = event_flags_.clear (mask, oflags);
595
596#if defined(OS_TRACE_RTOS_EVFLAGS)
597 trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
598 event_flags_.mask ());
599#endif
600
601 return res;
602
603#endif
604 }
605
619 {
620#if defined(OS_TRACE_RTOS_EVFLAGS)
621 trace::printf ("%s(0x%X) @%p %s \n", __func__, mask, this, name ());
622#endif
623
624#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
625
626 return port::event_flags::get (this, mask, mode);
627
628#else
629
630 flags::mask_t ret = event_flags_.get (mask, mode);
631
632#if defined(OS_TRACE_RTOS_EVFLAGS)
633 trace::printf ("%s(0x%X)=0x%X @%p %s \n", __func__, mask,
634 event_flags_.mask (), this, name ());
635#endif
636 // Return the selected flags.
637 return ret;
638
639#endif
640 }
641
645 bool
647 {
648#if defined(OS_TRACE_RTOS_EVFLAGS)
649 trace::printf ("%s() @%p %s\n", __func__, this, name ());
650#endif
651
652#if defined(OS_USE_RTOS_PORT_EVENT_FLAGS)
653
654 return port::event_flags::waiting (this);
655
656#else
657
658 // Don't call this from high priority interrupts.
659 assert(port::interrupts::is_priority_valid ());
660
661 {
662 // ----- Enter critical section -------------------------------------
664
665 return !list_.empty ();
666 // ----- Exit critical section --------------------------------------
667 }
668
669#endif
670 }
671
672 // --------------------------------------------------------------------------
673
674 } /* namespace rtos */
675} /* namespace os */
676
677// ----------------------------------------------------------------------------
Event flags attributes.
Definition os-evflags.h:69
Synchronised event flags.
Definition os-evflags.h:58
result_t wait(flags::mask_t mask, flags::mask_t *oflags, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Wait for event flags.
result_t timed_wait(flags::mask_t mask, clock::duration_t timeout, flags::mask_t *oflags=nullptr, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Timed wait for event flags.
~event_flags()
Destruct the event flags object instance.
event_flags(const attributes &attr=initializer)
Construct an event flags object instance.
bool waiting(void)
Check if there are threads waiting.
flags::mask_t get(flags::mask_t mask, flags::mode_t mode=flags::mode::clear)
Get (and possibly clear) event flags.
result_t try_wait(flags::mask_t mask, flags::mask_t *oflags=nullptr, flags::mode_t mode=flags::mode::all|flags::mode::clear)
Try to wait for event flags.
result_t raise(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Raise event flags.
result_t clear(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Clear event flags.
Ordered list of time stamp nodes.
Definition os-lists.h:671
const char * name(void) const
Get object name.
Definition os-decls.h:759
Double linked list node, with time stamp and thread.
Definition os-lists.h:223
Double linked list node, with thread reference.
Definition os-lists.h:60
Interrupts critical section RAII helper.
Definition os-sched.h:498
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:250
bool interrupted(void)
Check if interrupted.
Definition os-thread.h:2367
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:60
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:76
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition os-clocks.h:85
clock_systick sysclock
The system clock object instance.
static const attributes initializer
Default event flags initialiser.
Definition os-evflags.h:122
uint32_t mode_t
Type of variables holding flags modes.
Definition os-decls.h:275
uint32_t mask_t
Type of variables holding flags masks.
Definition os-decls.h:265
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1108
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:181
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:856
thread & thread(void)
Get the current running thread.
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:96
System namespace.
#define os_assert_throw(__e, __er)
Assert or throw a system error exception.
Definition os-decls.h:1130
#define os_assert_err(__e, __er)
Assert or return an error.
Definition os-decls.h:1115
Single file µOS++ RTOS definitions.