µ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-core.cpp
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#if defined(OS_USE_OS_APP_CONFIG_H)
13#include <cmsis-plus/os-app-config.h>
14#endif
15
16#include <cmsis-plus/rtos/os.h>
17
18// ----------------------------------------------------------------------------
19
20#if defined(__clang__)
21#pragma clang diagnostic ignored "-Wc++98-compat"
22#endif
23
24// ----------------------------------------------------------------------------
25
26namespace
27{
28#if defined(OS_HAS_INTERRUPTS_STACK)
29 // Object used to manage the interrupts stack.
30 class os::rtos::thread::stack interrupts_stack;
31#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
32} // namespace
33
34namespace os
35{
41 namespace rtos
42 {
43
49 namespace scheduler
50 {
60 bool is_started_ = false;
61
62#if 0
68 state_t lock_state_ = state::init;
69#endif
70
71#pragma GCC diagnostic push
72#if defined(__clang__)
73#pragma clang diagnostic ignored "-Wglobal-constructors"
74#pragma clang diagnostic ignored "-Wexit-time-destructors"
75#endif
82 // top_threads_list top_threads_list_;
83 thread::threads_list top_threads_list_;
84
85#pragma GCC diagnostic pop
86
87#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
88
89 bool is_preemptive_ = false;
90
91#pragma GCC diagnostic push
92#if defined(__clang__)
93#pragma clang diagnostic ignored "-Wpadded"
94#elif defined(__GNUC__)
95#pragma GCC diagnostic ignored "-Wpadded"
96#endif
97 // A small kludge to provide a temporary errno before
98 // the first real thread is created.
99 typedef struct
100 {
101 void* vtbl;
102 void* name_;
103 // errno is the first thread member, so right after the name.
104 int errno_;
105 } tiny_thread_t;
106#pragma GCC diagnostic pop
107
108 // Ensure the tiny thread is large enough to have the errno
109 // member in the same location.
110#pragma GCC diagnostic push
111#if defined(__clang__)
112#pragma clang diagnostic ignored "-Winvalid-offsetof"
113#elif defined(__GNUC__)
114#pragma GCC diagnostic ignored "-Winvalid-offsetof"
115#endif
116 static_assert (offsetof (tiny_thread_t, errno_)
117 == offsetof (thread, errno_),
118 "adjust tiny_thread_t members");
119#pragma GCC diagnostic pop
120
121#pragma GCC diagnostic push
122#if defined(__clang__)
123#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
124#endif
125 tiny_thread_t tiny_thread;
126#pragma GCC diagnostic pop
127
128#pragma GCC diagnostic push
129#pragma GCC diagnostic ignored "-Wcast-align"
130 thread* volatile current_thread_
131 = reinterpret_cast<thread*> (&tiny_thread);
132#pragma GCC diagnostic pop
133
134#pragma GCC diagnostic push
135#if defined(__clang__)
136#pragma clang diagnostic ignored "-Wglobal-constructors"
137#pragma clang diagnostic ignored "-Wexit-time-destructors"
138#endif
139 internal::ready_threads_list ready_threads_list_;
140#pragma GCC diagnostic pop
141#endif
142
143#pragma GCC diagnostic push
144#if defined(__clang__)
145#pragma clang diagnostic ignored "-Wglobal-constructors"
146#pragma clang diagnostic ignored "-Wexit-time-destructors"
147#endif
148 internal::terminated_threads_list terminated_threads_list_;
149#pragma GCC diagnostic pop
150
165 {
166#if defined(OS_TRACE_RTOS_SCHEDULER)
167 trace::printf ("scheduler::%s() \n", __func__);
168#endif
169
170 // Don't call this from interrupt handlers.
172
173#if defined(OS_USE_RTOS_PORT_SCHEDULER)
174
176
177#else
178
180
181 return result::ok;
182#endif
183 }
184
192 [[noreturn]] void
193 start (void)
194 {
195 trace::printf ("scheduler::%s() \n", __func__);
196
197 // Don't call this from interrupt handlers.
199
200 sysclock.start ();
201 hrclock.start ();
202
203 rtclock.start ();
204
205#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
206
207 scheduler::statistics::context_switches_ = 0;
208
209#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
210
211#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
212
213 scheduler::statistics::cpu_cycles_ = 0;
214 scheduler::statistics::switch_timestamp_ = hrclock.now ();
215
216#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
217
218#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
219 is_preemptive_ = OS_BOOL_RTOS_SCHEDULER_PREEMPTIVE;
220#endif /* defined(OS_USE_RTOS_PORT_SCHEDULER) */
221
222 is_started_ = true;
223
225 }
226
230 bool
231 preemptive (bool state)
232 {
233#if defined(OS_TRACE_RTOS_SCHEDULER)
234 trace::printf ("scheduler::%s(%d) \n", __func__, state);
235#endif
236 // Don't call this from interrupt handlers.
238
239#if defined(OS_USE_RTOS_PORT_SCHEDULER)
240
241 return port::scheduler::preemptive (state);
242
243#else
244 bool tmp;
245
246 {
247 // ----- Enter critical section -------------------------------------
249
250 tmp = is_preemptive_;
251 is_preemptive_ = state;
252 // ----- Exit critical section --------------------------------------
253 }
254
255 return tmp;
256#endif
257 }
258
264 thread::threads_list&
266 {
267 if (th == nullptr)
268 {
269 return top_threads_list_;
270 }
271 else
272 {
273 return th->children_;
274 }
275 }
276
314 /*
315 * @var const state_t critical_section::state_
316
317 * @details
318 * The variable is constant, after being set by the constructor no
319 * further changes are possible.
320 *
321 * The variable type usually is a `bool`, but a counter is also
322 * possible if the scheduler uses a recursive lock.
323 */
324
332 } /* namespace scheduler */
333
334 namespace scheduler
335 {
340 void
341 internal_link_node (internal::waiting_threads_list& list,
342 internal::waiting_thread_node& node)
343 {
344 // Remove this thread from the ready list, if there.
346
347 // Add this thread to the node waiting list.
348 list.link (node);
349 node.thread_->waiting_node_ = &node;
350
351 node.thread_->state_ = thread::state::suspended;
352 }
353
354 void
355 internal_unlink_node (internal::waiting_thread_node& node)
356 {
357 {
358 // ----- Enter critical section -------------------------------------
359 interrupts::critical_section ics;
360
361 // Remove the thread from the node waiting list,
362 // if not already removed.
363 node.thread_->waiting_node_ = nullptr;
364 node.unlink ();
365 // ----- Exit critical section --------------------------------------
366 }
367 }
368
369 void
370 internal_link_node (internal::waiting_threads_list& list,
371 internal::waiting_thread_node& node,
372 internal::clock_timestamps_list& timeout_list,
373 internal::timeout_thread_node& timeout_node)
374 {
375 // Remove this thread from the ready list, if there.
377
378 // Add this thread to the node waiting list.
379 list.link (node);
380 node.thread_->waiting_node_ = &node;
381
382 node.thread_->state_ = thread::state::suspended;
383
384 // Add this thread to the clock timeout list.
385 timeout_list.link (timeout_node);
386 timeout_node.thread.clock_node_ = &timeout_node;
387 }
388
389 void
390 internal_unlink_node (internal::waiting_thread_node& node,
391 internal::timeout_thread_node& timeout_node)
392 {
393 // ----- Enter critical section ---------------------------------------
394 interrupts::critical_section ics;
395
396 // Remove the thread from the clock timeout list,
397 // if not already removed by the timer.
398 timeout_node.thread.clock_node_ = nullptr;
399 timeout_node.unlink ();
400
401 // Remove the thread from the node waiting list,
402 // if not already removed.
403 node.thread_->waiting_node_ = nullptr;
404 node.unlink ();
405 // ----- Exit critical section ----------------------------------------
406 }
407
408 // ----------------------------------------------------------------------
409
410#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
411
412 void
413 internal_switch_threads (void)
414 {
415#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
416
417 // Get the high resolution timestamp.
419
420#pragma GCC diagnostic push
421#if defined(__clang__)
422#elif defined(__GNUC__)
423#pragma GCC diagnostic ignored "-Wuseless-cast"
424#endif
425
426 // Compute duration since previous context switch.
427 // Assume scheduler is not disabled for very long.
429 = static_cast<rtos::statistics::duration_t> (
430 now - scheduler::statistics::switch_timestamp_);
431
432#pragma GCC diagnostic pop
433
434 // Accumulate durations to scheduler total.
435 scheduler::statistics::cpu_cycles_ += delta;
436
437 // Accumulate durations to old thread.
438 scheduler::current_thread_->statistics_.cpu_cycles_ += delta;
439
440 // Remember the timestamp for the next context switch.
441 scheduler::statistics::switch_timestamp_ = now;
442
443#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
444
445 // The very core of the scheduler, if not locked, re-link the
446 // current thread and return the top priority thread.
447 if (!locked ())
448 {
449 // Normally the old running thread must be re-linked to ready.
450 scheduler::current_thread_->internal_relink_running_ ();
451
452 // The top of the ready list gives the next thread to run.
453 scheduler::current_thread_
454 = scheduler::ready_threads_list_.unlink_head ();
455 }
456
457 // ***** Pointer switched to new thread! *****
458
459 // The new thread was marked as running in unlink_head(),
460 // so in case the handler is re-entered immediately,
461 // the relink_running() will simply reschedule it,
462 // otherwise the thread will be lost.
463
464#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
465
466 // Increment global context switches.
467 scheduler::statistics::context_switches_++;
468
469 // Increment new thread context switches.
470 scheduler::current_thread_->statistics_.context_switches_++;
471
472#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
473 }
474
475#endif /* !defined(OS_USE_RTOS_PORT_SCHEDULER) */
476
477 namespace statistics
478 {
479#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
480
481 rtos::statistics::counter_t context_switches_;
482
483#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
484
485#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
486
487 clock::timestamp_t switch_timestamp_;
489
490#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
491
492 } /* namespace statistics */
493
498 } /* namespace scheduler */
499
505 namespace interrupts
506 {
544 /*
545 * @var const state_t critical_section::state_
546
547 * @details
548 * The variable is constant, after being set by the constructor no
549 * further changes are possible.
550 *
551 * The variable type usually is an unsigned integer where
552 * the priorities register is saved.
553 */
554
562 /*
563 * @var state_t lockable::state_
564
565 * @details
566 * The variable type usually is an unsigned integer where
567 * the priorities register is saved.
568 */
569
570#if defined(OS_HAS_INTERRUPTS_STACK) || defined(__DOXYGEN__)
571
582 class thread::stack*
583 stack (void)
584 {
585 return &interrupts_stack;
586 }
587
588#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
589
590 } /* namespace interrupts */
591
592 // ========================================================================
593 namespace internal
594 {
605 /*
606 * @var const char* const object_named::name_
607
608 * @details
609 * To save space, the null terminated string passed to the
610 * constructor is not copied locally. Instead, the pointer to
611 * the string is copied, so the
612 * caller must ensure that the pointer life cycle
613 * is at least as long as the object life cycle. A constant
614 * string (stored in flash) is preferred.
615 */
616
621 {
622 }
623
635 object_named::object_named (const char* name)
636 : name_ (name != nullptr ? name : "-")
637 {
638 }
639
640 } /* namespace internal */
641
642 // ========================================================================
643 } /* namespace rtos */
644} /* namespace os */
645
646#pragma GCC diagnostic push
647#if defined(__clang__)
648#pragma clang diagnostic ignored "-Wreserved-identifier"
649#elif defined(__GNUC__)
650#pragma GCC diagnostic ignored "-Wredundant-decls"
651#endif
652int*
653__errno (void);
654#pragma GCC diagnostic pop
655
671int*
673{
675}
676
681// ----------------------------------------------------------------------------
virtual void start(void) override
Start the clock.
virtual timestamp_t now(void) override
Tell the current time.
virtual void start(void) override
Initialise and make the RTC tick.
virtual void start(void) override
Start the clock.
object_named()
Construct a named object instance.
Definition os-core.cpp:620
Interrupts critical section RAII helper.
Definition os-sched.h:502
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:251
Standard thread.
#define OS_BOOL_RTOS_SCHEDULER_PREEMPTIVE
Default definition for the pre-emption flag.
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:59
int * __errno(void)
Per-thread error support.
Definition os-core.cpp:672
clock_highres hrclock
The high resolution clock object instance.
clock_rtc rtclock
The real time clock object instance.
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition os-clocks.h:88
clock_systick sysclock
The system clock object instance.
class thread::stack * stack(void)
Get the interrupts stack.
Definition os-core.cpp:583
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1101
result_t initialize(void)
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:179
port::scheduler::state_t state_t
Type of variables holding scheduler state codes.
Definition os-decls.h:200
void start(void)
Start the RTOS scheduler.
Definition os-core.cpp:193
thread::threads_list & children_threads(thread *th)
Get the children threads.
Definition os-core.cpp:265
result_t initialize(void)
Initialise the RTOS scheduler.
Definition os-core.cpp:164
bool preemptive(void)
Check if the scheduler is in preemptive mode.
Definition os-sched.h:841
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:858
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition os-decls.h:220
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:215
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2106
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:95
System namespace.
#define os_assert_throw(__e, __er)
Assert or throw a system error exception.
Definition os-decls.h:1122
#define os_assert_err(__e, __er)
Assert or return an error.
Definition os-decls.h:1101
Single file µOS++ RTOS definitions.
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:390