µ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-semaphore.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 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#include <cmsis-plus/rtos/os.h>
29
30// ----------------------------------------------------------------------------
31
32#if defined(__clang__)
33#pragma clang diagnostic ignored "-Wc++98-compat"
34#endif
35
36// ----------------------------------------------------------------------------
37
38namespace os
39{
40 namespace rtos
41 {
42 // ------------------------------------------------------------------------
43
97 const semaphore::attributes_binary semaphore::initializer_binary
98 { 0 };
99
100 // ------------------------------------------------------------------------
101
161 semaphore::semaphore (const char* name, const attributes& attr) :
163 { name, attr.sm_max_value, attr.sm_initial_value, attr }
164 {
165 ;
166 }
167
172 semaphore::semaphore (const char* name, const count_t max_value,
173 const count_t initial_value, const attributes& attr
175 __attribute__((unused))
176#endif
177 ) :
178 object_named_system
179 { name }, //
180 max_value_ (max_value), //
181 initial_value_ (initial_value)
182 {
183#if defined(OS_TRACE_RTOS_SEMAPHORE)
184 trace::printf ("%s() @%p %s %u %u\n", __func__, this, this->name (),
185 initial_value, max_value_);
186#endif
187
188 // Don't call this from interrupt handlers.
190
191 // The CMSIS validator requires the max_value to be equal to
192 // the initial count, which can be 0, but we patch it on the way.
193 assert(max_value_ > 0);
194 assert(initial_value >= 0);
195 assert(initial_value <= max_value_);
196
197 count_ = initial_value;
198
199#if !defined(OS_USE_RTOS_PORT_SEMAPHORE)
200 clock_ = attr.clock != nullptr ? attr.clock : &sysclock;
201#endif
202
203#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
204
205 port::semaphore::create (this);
206
207#else
208
209 internal_init_ ();
210
211#endif
212 }
213
237 {
238#if defined(OS_TRACE_RTOS_SEMAPHORE)
239 trace::printf ("%s() @%p %s\n", __func__, this, name ());
240#endif
241
242#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
243
244 port::semaphore::destroy (this);
245
246#else
247
248 // There must be no threads waiting for this semaphore.
249 assert(list_.empty ());
250
251#endif
252 }
253
258 void
259 semaphore::internal_init_ (void)
260 {
261
262 count_ = initial_value_;
263
264#if !defined(OS_USE_RTOS_PORT_SEMAPHORE)
265
266 // Wake-up all threads, if any.
267 // Need not be inside the critical section,
268 // the list is protected by inner `resume_one()`.
269 list_.resume_all ();
270
271#endif /* !defined(OS_USE_RTOS_PORT_SEMAPHORE) */
272 }
273
274 /*
275 * Internal function.
276 * Should be called from an interrupts critical section.
277 */
278 bool
279 semaphore::internal_try_wait_ (void)
280 {
281 if (count_ > 0)
282 {
283#pragma GCC diagnostic push
284#if defined(__clang__)
285#pragma clang diagnostic ignored "-Wdeprecated-volatile"
286#endif
287 --count_;
288#pragma GCC diagnostic pop
289
290#if defined(OS_TRACE_RTOS_SEMAPHORE)
291 trace::printf ("%s() @%p %s >%u\n", __func__, this, name (), count_);
292#endif
293 return true;
294 }
295
296 // Count may be 0.
297#if defined(OS_TRACE_RTOS_SEMAPHORE)
298 trace::printf ("%s() @%p %s false\n", __func__, this, name ());
299#endif
300 return false;
301 }
302
346 {
347
348#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
349
350#if defined(OS_TRACE_RTOS_SEMAPHORE)
351 trace::printf ("%s() @%p %s\n", __func__, this, name ());
352#endif
353
354 return port::semaphore::post (this);
355
356#else
357
358 // Don't call this from high priority interrupts.
359 assert(port::interrupts::is_priority_valid ());
360
361 {
362 // ----- Enter critical section -------------------------------------
364
365 if (count_ >= this->max_value_)
366 {
367#if defined(OS_TRACE_RTOS_SEMAPHORE)
368 trace::printf ("%s() @%p %s EAGAIN\n", __func__, this, name ());
369#endif
370 return EAGAIN;
371 }
372
373#pragma GCC diagnostic push
374#if defined(__clang__)
375#pragma clang diagnostic ignored "-Wdeprecated-volatile"
376#endif
377 ++count_;
378#pragma GCC diagnostic pop
379
380#if defined(OS_TRACE_RTOS_SEMAPHORE)
381 trace::printf ("%s() @%p %s count %u\n", __func__, this, name (),
382 count_);
383#endif
384 // ----- Exit critical section --------------------------------------
385 }
386
387 // Wake-up one thread.
388 list_.resume_one ();
389
390 return result::ok;
391
392#endif
393 }
394
425 {
426#if defined(OS_TRACE_RTOS_SEMAPHORE)
427 trace::printf ("%s() @%p %s <%u\n", __func__, this, name (), count_);
428#endif
429
430 // Don't call this from interrupt handlers.
432 // Don't call this from critical regions.
434
435#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
436
437 return port::semaphore::wait (this);
438
439#else
440
441 // Extra test before entering the loop, with its inherent weight.
442 // Trade size for speed.
443 {
444 // ----- Enter critical section -------------------------------------
446
447 if (internal_try_wait_ ())
448 {
449 return result::ok;
450 }
451 // ----- Exit critical section --------------------------------------
452 }
453
454 thread& crt_thread = this_thread::thread ();
455
456 // Prepare a list node pointing to the current thread.
457 // Do not worry for being on stack, it is temporarily linked to the
458 // list and guaranteed to be removed before this function returns.
460 { crt_thread };
461
462 for (;;)
463 {
464 {
465 // ----- Enter critical section ---------------------------------
467
468 if (internal_try_wait_ ())
469 {
470 return result::ok;
471 }
472
473 // Add this thread to the semaphore waiting list.
474 scheduler::internal_link_node (list_, node);
475 // state::suspended set in above link().
476 // ----- Exit critical section ----------------------------------
477 }
478
480
481 // Remove the thread from the semaphore waiting list,
482 // if not already removed by post().
483 scheduler::internal_unlink_node (node);
484
485 if (crt_thread.interrupted ())
486 {
487#if defined(OS_TRACE_RTOS_SEMAPHORE)
488 trace::printf ("%s() EINTR @%p %s\n", __func__, this, name ());
489#endif
490 return EINTR;
491 }
492 }
493
494 /* NOTREACHED */
495 return ENOTRECOVERABLE;
496
497#endif
498 }
499
522 {
523#if defined(OS_TRACE_RTOS_SEMAPHORE)
524 trace::printf ("%s() @%p %s <%u\n", __func__, this, name (), count_);
525#endif
526
527 // Don't call this from high priority interrupts.
528 assert(port::interrupts::is_priority_valid ());
529
530#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
531
532 return port::semaphore::try_wait (this);
533
534#else
535
536 {
537 // ----- Enter critical section -------------------------------------
539
540 if (internal_try_wait_ ())
541 {
542 return result::ok;
543 }
544 else
545 {
546 return EWOULDBLOCK;
547 }
548 // ----- Exit critical section --------------------------------------
549 }
550
551#endif
552 }
553
592 {
593#if defined(OS_TRACE_RTOS_SEMAPHORE)
594 trace::printf ("%s(%u) @%p %s <%u\n", __func__,
595 static_cast<unsigned int> (timeout), this, name (),
596 count_);
597#endif
598
599 // Don't call this from interrupt handlers.
601 // Don't call this from critical regions.
603
604#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
605
606 return port::semaphore::timed_wait (this, timeout);
607
608#else
609
610 // Extra test before entering the loop, with its inherent weight.
611 // Trade size for speed.
612 {
613 // ----- Enter critical section -------------------------------------
615
616 if (internal_try_wait_ ())
617 {
618 return result::ok;
619 }
620 // ----- Exit critical section --------------------------------------
621 }
622
623 thread& crt_thread = this_thread::thread ();
624
625 // Prepare a list node pointing to the current thread.
626 // Do not worry for being on stack, it is temporarily linked to the
627 // list and guaranteed to be removed before this function returns.
629 { crt_thread };
630
631 internal::clock_timestamps_list& clock_list = clock_->steady_list ();
632 clock::timestamp_t timeout_timestamp = clock_->steady_now () + timeout;
633
634 // Prepare a timeout node pointing to the current thread.
636 { timeout_timestamp, crt_thread };
637
638 for (;;)
639 {
640 {
641 // ----- Enter critical section ---------------------------------
643
644 if (internal_try_wait_ ())
645 {
646 return result::ok;
647 }
648
649 // Add this thread to the semaphore waiting list,
650 // and the clock timeout list.
651 scheduler::internal_link_node (list_, node, clock_list,
652 timeout_node);
653 // state::suspended set in above link().
654 // ----- Exit critical section ----------------------------------
655 }
656
658
659 // Remove the thread from the semaphore waiting list,
660 // if not already removed by post() and from the clock
661 // timeout list, if not already removed by the timer.
662 scheduler::internal_unlink_node (node, timeout_node);
663
664 if (crt_thread.interrupted ())
665 {
666#if defined(OS_TRACE_RTOS_SEMAPHORE)
667 trace::printf ("%s(%u) EINTR @%p %s\n", __func__,
668 static_cast<unsigned int> (timeout), this,
669 name ());
670#endif
671 return EINTR;
672 }
673
674 if (clock_->steady_now () >= timeout_timestamp)
675 {
676#if defined(OS_TRACE_RTOS_SEMAPHORE)
677 trace::printf ("%s(%u) ETIMEDOUT @%p %s\n", __func__,
678 static_cast<unsigned int> (timeout), this,
679 name ());
680#endif
681 return ETIMEDOUT;
682 }
683 }
684
685 /* NOTREACHED */
686 return ENOTRECOVERABLE;
687
688#endif
689 }
690
713 semaphore::value (void) const
714 {
715#if !defined(OS_USE_RTOS_PORT_SEMAPHORE)
716 return (count_ > 0) ? count_ : 0;
717#else
718 return count_;
719#endif
720 }
721
733 {
734#if defined(OS_TRACE_RTOS_SEMAPHORE)
735 trace::printf ("%s() @%p %s <%u\n", __func__, this, name (), count_);
736#endif
737
738 // Don't call this from interrupt handlers.
740
741#if defined(OS_USE_RTOS_PORT_SEMAPHORE)
742
743 return port::semaphore::reset (this);
744
745#else
746
747 {
748 // ----- Enter critical section -------------------------------------
750
751 internal_init_ ();
752 return result::ok;
753 // ----- Exit critical section --------------------------------------
754 }
755
756#endif
757 }
758
759 // --------------------------------------------------------------------------
760
761 } /* namespace rtos */
762} /* namespace os */
763
764// ----------------------------------------------------------------------------
Ordered list of time stamp nodes.
Definition os-lists.h:671
const char * name(void) const
Get object name.
Definition os-decls.h:774
Double linked list node, with time stamp and thread.
Definition os-lists.h:227
Double linked list node, with thread reference.
Definition os-lists.h:72
Interrupts critical section RAII helper.
Definition os-sched.h:524
Semaphore attributes.
count_t sm_max_value
Semaphore max count value.
count_t sm_initial_value
Semaphore initial count value.
POSIX compliant semaphore.
result_t timed_wait(clock::duration_t timeout)
Timed wait to lock the semaphore.
result_t wait(void)
Lock the semaphore, possibly waiting.
result_t reset(void)
Reset the semaphore.
result_t post(void)
Post (unlock) the semaphore.
result_t try_wait(void)
Try to lock the semaphore.
~semaphore()
Destruct the semaphore object instance.
semaphore(const attributes &attr=initializer_binary)
Construct a semaphore object instance.
count_t value(void) const
Get the semaphore count value.
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:247
bool interrupted(void)
Check if interrupted.
Definition os-thread.h:2361
#define OS_USE_RTOS_PORT_SEMAPHORE
Use a custom semaphore implementation.
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:83
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition os-clocks.h:92
clock_systick sysclock
The system clock object instance.
static const attributes_binary initializer_binary
Default binary semaphore initialiser.
int16_t count_t
Type of semaphore counter storage.
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1136
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:195
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:882
thread & thread(void)
Get the current running thread.
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:110
System namespace.
#define os_assert_throw(__e, __er)
Assert or throw a system error exception.
Definition os-decls.h:1141
#define os_assert_err(__e, __er)
Assert or return an error.
Definition os-decls.h:1126
Single file µOS++ RTOS definitions.