µ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++ 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
28{
29#if defined(OS_HAS_INTERRUPTS_STACK)
30// Object used to manage the interrupts stack.
31 class os::rtos::thread::stack interrupts_stack;
32#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
33}
34
35namespace os
36{
42 namespace rtos
43 {
44
50 namespace scheduler
51 {
61 bool is_started_ = false;
62
63#if 0
69 state_t lock_state_ = state::init;
70#endif
71
72#pragma GCC diagnostic push
73#if defined(__clang__)
74#pragma clang diagnostic ignored "-Wglobal-constructors"
75#pragma clang diagnostic ignored "-Wexit-time-destructors"
76#endif
83 // top_threads_list top_threads_list_;
84 thread::threads_list top_threads_list_;
85
86#pragma GCC diagnostic pop
87
88#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
89
90 bool is_preemptive_ = false;
91
92#pragma GCC diagnostic push
93#if defined(__clang__)
94#pragma clang diagnostic ignored "-Wpadded"
95#elif defined(__GNUC__)
96#pragma GCC diagnostic ignored "-Wpadded"
97#endif
98 // A small kludge to provide a temporary errno before
99 // the first real thread is created.
100 typedef struct {
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#elif defined(__GNUC__)
113#pragma GCC diagnostic ignored "-Winvalid-offsetof"
114#endif
115 static_assert(offsetof(tiny_thread_t, errno_) == offsetof(thread, errno_), "adjust tiny_thread_t members");
116#pragma GCC diagnostic pop
117
118#pragma GCC diagnostic push
119#if defined(__clang__)
120#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
121#endif
122 tiny_thread_t tiny_thread;
123#pragma GCC diagnostic pop
124
125#pragma GCC diagnostic push
126#pragma GCC diagnostic ignored "-Wcast-align"
127 thread* volatile current_thread_ = reinterpret_cast<thread*>(&tiny_thread);
128#pragma GCC diagnostic pop
129
130#pragma GCC diagnostic push
131#if defined(__clang__)
132#pragma clang diagnostic ignored "-Wglobal-constructors"
133#pragma clang diagnostic ignored "-Wexit-time-destructors"
134#endif
135 internal::ready_threads_list ready_threads_list_;
136#pragma GCC diagnostic pop
137#endif
138
139#pragma GCC diagnostic push
140#if defined(__clang__)
141#pragma clang diagnostic ignored "-Wglobal-constructors"
142#pragma clang diagnostic ignored "-Wexit-time-destructors"
143#endif
144 internal::terminated_threads_list terminated_threads_list_;
145#pragma GCC diagnostic pop
146
161 {
162#if defined(OS_TRACE_RTOS_SCHEDULER)
163 trace::printf ("scheduler::%s() \n", __func__);
164#endif
165
166 // Don't call this from interrupt handlers.
168
169#if defined(OS_USE_RTOS_PORT_SCHEDULER)
170
172
173#else
174
176
177 return result::ok;
178#endif
179 }
180
188 [[noreturn]] void
189 start (void)
190 {
191 trace::printf ("scheduler::%s() \n", __func__);
192
193 // Don't call this from interrupt handlers.
195
196 sysclock.start ();
197 hrclock.start ();
198
199 rtclock.start ();
200
201#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
202
203 scheduler::statistics::context_switches_ = 0;
204
205#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
206
207#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
208
209 scheduler::statistics::cpu_cycles_ = 0;
210 scheduler::statistics::switch_timestamp_ = hrclock.now ();
211
212#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
213
214#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
215 is_preemptive_ = OS_BOOL_RTOS_SCHEDULER_PREEMPTIVE;
216#endif /* defined(OS_USE_RTOS_PORT_SCHEDULER) */
217
218 is_started_ = true;
219
221 }
222
226 bool
227 preemptive (bool state)
228 {
229#if defined(OS_TRACE_RTOS_SCHEDULER)
230 trace::printf ("scheduler::%s(%d) \n", __func__, state);
231#endif
232 // Don't call this from interrupt handlers.
234
235#if defined(OS_USE_RTOS_PORT_SCHEDULER)
236
237 return port::scheduler::preemptive(state);
238
239#else
240 bool tmp;
241
242 {
243 // ----- Enter critical section -----------------------------------
245
246 tmp = is_preemptive_;
247 is_preemptive_ = state;
248 // ----- Exit critical section ------------------------------------
249 }
250
251 return tmp;
252#endif
253 }
254
260 thread::threads_list&
262 {
263 if (th == nullptr)
264 {
265 return top_threads_list_;
266 }
267 else
268 {
269 return th->children_;
270 }
271 }
272
308 /*
309 * @var const state_t critical_section::state_
310 * @details
311 * The variable is constant, after being set by the constructor no
312 * further changes are possible.
313 *
314 * The variable type usually is a `bool`, but a counter is also
315 * possible if the scheduler uses a recursive lock.
316 */
317
324 } /* namespace scheduler */
325
326 namespace scheduler
327 {
332 void
333 internal_link_node (internal::waiting_threads_list& list,
334 internal::waiting_thread_node& node)
335 {
336 // Remove this thread from the ready list, if there.
338
339 // Add this thread to the node waiting list.
340 list.link (node);
341 node.thread_->waiting_node_ = &node;
342
343 node.thread_->state_ = thread::state::suspended;
344 }
345
346 void
347 internal_unlink_node (internal::waiting_thread_node& node)
348 {
349 {
350 // ----- Enter critical section -----------------------------------
351 interrupts::critical_section ics;
352
353 // Remove the thread from the node waiting list,
354 // if not already removed.
355 node.thread_->waiting_node_ = nullptr;
356 node.unlink ();
357 // ----- Exit critical section ------------------------------------
358 }
359 }
360
361 void
362 internal_link_node (internal::waiting_threads_list& list,
363 internal::waiting_thread_node& node,
364 internal::clock_timestamps_list& timeout_list,
365 internal::timeout_thread_node& timeout_node)
366 {
367 // Remove this thread from the ready list, if there.
369
370 // Add this thread to the node waiting list.
371 list.link (node);
372 node.thread_->waiting_node_ = &node;
373
374 node.thread_->state_ = thread::state::suspended;
375
376 // Add this thread to the clock timeout list.
377 timeout_list.link (timeout_node);
378 timeout_node.thread.clock_node_ = &timeout_node;
379 }
380
381 void
382 internal_unlink_node (internal::waiting_thread_node& node,
383 internal::timeout_thread_node& timeout_node)
384 {
385 // ----- Enter critical section ---------------------------------------
386 interrupts::critical_section ics;
387
388 // Remove the thread from the clock timeout list,
389 // if not already removed by the timer.
390 timeout_node.thread.clock_node_ = nullptr;
391 timeout_node.unlink ();
392
393 // Remove the thread from the node waiting list,
394 // if not already removed.
395 node.thread_->waiting_node_ = nullptr;
396 node.unlink ();
397 // ----- Exit critical section ----------------------------------------
398 }
399
400 // ----------------------------------------------------------------------
401
402#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
403
404 void
405 internal_switch_threads (void)
406 {
407#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
408
409 // Get the high resolution timestamp.
411
412#pragma GCC diagnostic push
413#if defined(__clang__)
414#elif defined(__GNUC__)
415#pragma GCC diagnostic ignored "-Wuseless-cast"
416#endif
417
418 // Compute duration since previous context switch.
419 // Assume scheduler is not disabled for very long.
421 static_cast<rtos::statistics::duration_t> (now
422 - scheduler::statistics::switch_timestamp_);
423
424#pragma GCC diagnostic pop
425
426 // Accumulate durations to scheduler total.
427 scheduler::statistics::cpu_cycles_ += delta;
428
429 // Accumulate durations to old thread.
430 scheduler::current_thread_->statistics_.cpu_cycles_ += delta;
431
432 // Remember the timestamp for the next context switch.
433 scheduler::statistics::switch_timestamp_ = now;
434
435#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
436
437 // The very core of the scheduler, if not locked, re-link the
438 // current thread and return the top priority thread.
439 if (!locked ())
440 {
441 // Normally the old running thread must be re-linked to ready.
442 scheduler::current_thread_->internal_relink_running_ ();
443
444 // The top of the ready list gives the next thread to run.
445 scheduler::current_thread_ =
446 scheduler::ready_threads_list_.unlink_head ();
447 }
448
449 // ***** Pointer switched to new thread! *****
450
451 // The new thread was marked as running in unlink_head(),
452 // so in case the handler is re-entered immediately,
453 // the relink_running() will simply reschedule it,
454 // otherwise the thread will be lost.
455
456#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
457
458 // Increment global context switches.
459 scheduler::statistics::context_switches_++;
460
461 // Increment new thread context switches.
462 scheduler::current_thread_->statistics_.context_switches_++;
463
464#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
465
466 }
467
468#endif /* !defined(OS_USE_RTOS_PORT_SCHEDULER) */
469
470 namespace statistics
471 {
472#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
473
474 rtos::statistics::counter_t context_switches_;
475
476#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
477
478#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
479
480 clock::timestamp_t switch_timestamp_;
482
483#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
484
485 } /* namespace statistics */
486
491 } /* namespace scheduler */
492
498 namespace interrupts
499 {
535 /*
536 * @var const state_t critical_section::state_
537 * @details
538 * The variable is constant, after being set by the constructor no
539 * further changes are possible.
540 *
541 * The variable type usually is an unsigned integer where
542 * the priorities register is saved.
543 */
544
551 /*
552 * @var state_t lockable::state_
553 * @details
554 * The variable type usually is an unsigned integer where
555 * the priorities register is saved.
556 */
557
558#if defined(OS_HAS_INTERRUPTS_STACK) || defined(__DOXYGEN__)
559
570 class thread::stack*
571 stack (void)
572 {
573 return &interrupts_stack;
574 }
575
576#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
577
578 } /* namespace interrupts */
579
580 // ========================================================================
581 namespace internal
582 {
592 /*
593 * @var const char* const object_named::name_
594 * @details
595 * To save space, the null terminated string passed to the
596 * constructor is not copied locally. Instead, the pointer to
597 * the string is copied, so the
598 * caller must ensure that the pointer life cycle
599 * is at least as long as the object life cycle. A constant
600 * string (stored in flash) is preferred.
601 */
602
607 {
608 }
609
621 object_named::object_named (const char* name) :
622 name_ (name != nullptr ? name : "-")
623 {
624 }
625
626 } /* namespace internal */
627
628 // ==========================================================================
629 } /* namespace rtos */
630} /* namespace os */
631
632#pragma GCC diagnostic push
633#if defined(__clang__)
634#pragma clang diagnostic ignored "-Wreserved-identifier"
635#elif defined(__GNUC__)
636#pragma GCC diagnostic ignored "-Wredundant-decls"
637#endif
638int*
639__errno (void);
640#pragma GCC diagnostic pop
641
656int*
658{
660}
661
666// ----------------------------------------------------------------------------
virtual void start(void) override
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
object_named()
Construct a named object instance.
Definition os-core.cpp:606
Interrupts critical section RAII helper.
Definition os-sched.h:498
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:250
Standard thread.
#define OS_BOOL_RTOS_SCHEDULER_PREEMPTIVE
Default definition for the preemption flag.
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:60
int * __errno(void)
Per-thread error support.
Definition os-core.cpp:657
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:85
clock_systick sysclock
The system clock object instance.
class thread::stack * stack(void)
Get the interrupts stack.
Definition os-core.cpp:571
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1108
result_t initialize(void)
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:181
port::scheduler::state_t state_t
Type of variables holding scheduler state codes.
Definition os-decls.h:202
void start(void)
Start the RTOS scheduler.
Definition os-core.cpp:189
thread::threads_list & children_threads(thread *th)
Get the children threads.
Definition os-core.cpp:261
result_t initialize(void)
Initialise the RTOS scheduler.
Definition os-core.cpp:160
bool preemptive(void)
Check if the scheduler is in preemptive mode.
Definition os-sched.h:839
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:856
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition os-decls.h:222
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:217
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2103
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.
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:389