µ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 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
39{
40#if defined(OS_HAS_INTERRUPTS_STACK)
41// Object used to manage the interrupts stack.
42 class os::rtos::thread::stack interrupts_stack;
43#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
44}
45
46namespace os
47{
53 namespace rtos
54 {
55
61 namespace scheduler
62 {
72 bool is_started_ = false;
73
74#if 0
80 state_t lock_state_ = state::init;
81#endif
82
83#pragma GCC diagnostic push
84#if defined(__clang__)
85#pragma clang diagnostic ignored "-Wglobal-constructors"
86#pragma clang diagnostic ignored "-Wexit-time-destructors"
87#endif
94 // top_threads_list top_threads_list_;
95 thread::threads_list top_threads_list_;
96
97#pragma GCC diagnostic pop
98
99#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
100
101 bool is_preemptive_ = false;
102
103#pragma GCC diagnostic push
104#pragma GCC diagnostic ignored "-Wpadded"
105 // A small kludge to provide a temporary errno before
106 // the first real thread is created.
107 typedef struct {
108 void* vtbl;
109 void* name_;
110 // errno is the first thread member, so right after the name.
111 int errno_;
112 } tiny_thread_t;
113#pragma GCC diagnostic pop
114
115 // Ensure the tiny thread is large enough to have the errno
116 // member in the same location.
117#pragma GCC diagnostic push
118#pragma GCC diagnostic ignored "-Winvalid-offsetof"
119 static_assert(offsetof(tiny_thread_t, errno_) == offsetof(thread, errno_), "adjust tiny_thread_t members");
120#pragma GCC diagnostic pop
121
122#pragma GCC diagnostic push
123#if defined(__clang__)
124#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
125#endif
126 tiny_thread_t tiny_thread;
127#pragma GCC diagnostic pop
128
129 thread* volatile current_thread_ = reinterpret_cast<thread*>(&tiny_thread);
130
131#pragma GCC diagnostic push
132#if defined(__clang__)
133#pragma clang diagnostic ignored "-Wglobal-constructors"
134#pragma clang diagnostic ignored "-Wexit-time-destructors"
135#endif
136 internal::ready_threads_list ready_threads_list_;
137#pragma GCC diagnostic pop
138#endif
139
140#pragma GCC diagnostic push
141#if defined(__clang__)
142#pragma clang diagnostic ignored "-Wglobal-constructors"
143#pragma clang diagnostic ignored "-Wexit-time-destructors"
144#endif
145 internal::terminated_threads_list terminated_threads_list_;
146#pragma GCC diagnostic pop
147
162 {
163#if defined(OS_TRACE_RTOS_SCHEDULER)
164 trace::printf ("scheduler::%s() \n", __func__);
165#endif
166
167 // Don't call this from interrupt handlers.
169
170#if defined(OS_USE_RTOS_PORT_SCHEDULER)
171
173
174#else
175
177
178 return result::ok;
179#endif
180 }
181
189 [[noreturn]] void
190 start (void)
191 {
192 trace::printf ("scheduler::%s() \n", __func__);
193
194 // Don't call this from interrupt handlers.
196
197 sysclock.start ();
198 hrclock.start ();
199
200 rtclock.start ();
201
202#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
203
204 scheduler::statistics::context_switches_ = 0;
205
206#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
207
208#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
209
210 scheduler::statistics::cpu_cycles_ = 0;
211 scheduler::statistics::switch_timestamp_ = hrclock.now ();
212
213#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
214
215#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
216 is_preemptive_ = OS_BOOL_RTOS_SCHEDULER_PREEMPTIVE;
217#endif /* defined(OS_USE_RTOS_PORT_SCHEDULER) */
218
219 is_started_ = true;
220
222 }
223
227 bool
228 preemptive (bool state)
229 {
230#if defined(OS_TRACE_RTOS_SCHEDULER)
231 trace::printf ("scheduler::%s(%d) \n", __func__, state);
232#endif
233 // Don't call this from interrupt handlers.
235
236#if defined(OS_USE_RTOS_PORT_SCHEDULER)
237
238 return port::scheduler::preemptive(state);
239
240#else
241 bool tmp;
242
243 {
244 // ----- Enter critical section -----------------------------------
246
247 tmp = is_preemptive_;
248 is_preemptive_ = state;
249 // ----- Exit critical section ------------------------------------
250 }
251
252 return tmp;
253#endif
254 }
255
261 thread::threads_list&
263 {
264 if (th == nullptr)
265 {
266 return top_threads_list_;
267 }
268 else
269 {
270 return th->children_;
271 }
272 }
273
309 /*
310 * @var const state_t critical_section::state_
311 * @details
312 * The variable is constant, after being set by the constructor no
313 * further changes are possible.
314 *
315 * The variable type usually is a `bool`, but a counter is also
316 * possible if the scheduler uses a recursive lock.
317 */
318
325 } /* namespace scheduler */
326
327 namespace scheduler
328 {
333 void
334 internal_link_node (internal::waiting_threads_list& list,
335 internal::waiting_thread_node& node)
336 {
337 // Remove this thread from the ready list, if there.
339
340 // Add this thread to the node waiting list.
341 list.link (node);
342 node.thread_->waiting_node_ = &node;
343
344 node.thread_->state_ = thread::state::suspended;
345 }
346
347 void
348 internal_unlink_node (internal::waiting_thread_node& node)
349 {
350 {
351 // ----- Enter critical section -----------------------------------
352 interrupts::critical_section ics;
353
354 // Remove the thread from the node waiting list,
355 // if not already removed.
356 node.thread_->waiting_node_ = nullptr;
357 node.unlink ();
358 // ----- Exit critical section ------------------------------------
359 }
360 }
361
362 void
363 internal_link_node (internal::waiting_threads_list& list,
364 internal::waiting_thread_node& node,
365 internal::clock_timestamps_list& timeout_list,
366 internal::timeout_thread_node& timeout_node)
367 {
368 // Remove this thread from the ready list, if there.
370
371 // Add this thread to the node waiting list.
372 list.link (node);
373 node.thread_->waiting_node_ = &node;
374
375 node.thread_->state_ = thread::state::suspended;
376
377 // Add this thread to the clock timeout list.
378 timeout_list.link (timeout_node);
379 timeout_node.thread.clock_node_ = &timeout_node;
380 }
381
382 void
383 internal_unlink_node (internal::waiting_thread_node& node,
384 internal::timeout_thread_node& timeout_node)
385 {
386 // ----- Enter critical section ---------------------------------------
387 interrupts::critical_section ics;
388
389 // Remove the thread from the clock timeout list,
390 // if not already removed by the timer.
391 timeout_node.thread.clock_node_ = nullptr;
392 timeout_node.unlink ();
393
394 // Remove the thread from the node waiting list,
395 // if not already removed.
396 node.thread_->waiting_node_ = nullptr;
397 node.unlink ();
398 // ----- Exit critical section ----------------------------------------
399 }
400
401 // ----------------------------------------------------------------------
402
403#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
404
405 void
406 internal_switch_threads (void)
407 {
408#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
409
410 // Get the high resolution timestamp.
412
413 // Compute duration since previous context switch.
414 // Assume scheduler is not disabled for very long.
416 static_cast<rtos::statistics::duration_t> (now
417 - scheduler::statistics::switch_timestamp_);
418
419 // Accumulate durations to scheduler total.
420 scheduler::statistics::cpu_cycles_ += delta;
421
422 // Accumulate durations to old thread.
423 scheduler::current_thread_->statistics_.cpu_cycles_ += delta;
424
425 // Remember the timestamp for the next context switch.
426 scheduler::statistics::switch_timestamp_ = now;
427
428#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
429
430 // The very core of the scheduler, if not locked, re-link the
431 // current thread and return the top priority thread.
432 if (!locked ())
433 {
434 // Normally the old running thread must be re-linked to ready.
435 scheduler::current_thread_->internal_relink_running_ ();
436
437 // The top of the ready list gives the next thread to run.
438 scheduler::current_thread_ =
439 scheduler::ready_threads_list_.unlink_head ();
440 }
441
442 // ***** Pointer switched to new thread! *****
443
444 // The new thread was marked as running in unlink_head(),
445 // so in case the handler is re-entered immediately,
446 // the relink_running() will simply reschedule it,
447 // otherwise the thread will be lost.
448
449#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
450
451 // Increment global context switches.
452 scheduler::statistics::context_switches_++;
453
454 // Increment new thread context switches.
455 scheduler::current_thread_->statistics_.context_switches_++;
456
457#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
458
459 }
460
461#endif /* !defined(OS_USE_RTOS_PORT_SCHEDULER) */
462
463 namespace statistics
464 {
465#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES)
466
467 rtos::statistics::counter_t context_switches_;
468
469#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CONTEXT_SWITCHES) */
470
471#if defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES)
472
473 clock::timestamp_t switch_timestamp_;
475
476#endif /* defined(OS_INCLUDE_RTOS_STATISTICS_THREAD_CPU_CYCLES) */
477
478 } /* namespace statistics */
479
484 } /* namespace scheduler */
485
491 namespace interrupts
492 {
528 /*
529 * @var const state_t critical_section::state_
530 * @details
531 * The variable is constant, after being set by the constructor no
532 * further changes are possible.
533 *
534 * The variable type usually is an unsigned integer where
535 * the priorities register is saved.
536 */
537
544 /*
545 * @var state_t lockable::state_
546 * @details
547 * The variable type usually is an unsigned integer where
548 * the priorities register is saved.
549 */
550
551#if defined(OS_HAS_INTERRUPTS_STACK) || defined(__DOXYGEN__)
552
563 class thread::stack*
564 stack (void)
565 {
566 return &interrupts_stack;
567 }
568
569#endif /* defined(OS_HAS_INTERRUPTS_STACK) */
570
571 } /* namespace interrupts */
572
573 // ========================================================================
574 namespace internal
575 {
585 /*
586 * @var const char* const object_named::name_
587 * @details
588 * To save space, the null terminated string passed to the
589 * constructor is not copied locally. Instead, the pointer to
590 * the string is copied, so the
591 * caller must ensure that the pointer life cycle
592 * is at least as long as the object life cycle. A constant
593 * string (stored in flash) is preferred.
594 */
595
600 {
601 ;
602 }
603
615 object_named::object_named (const char* name) :
616 name_ (name != nullptr ? name : "-")
617 {
618 ;
619 }
620
621 } /* namespace internal */
622
623 // ==========================================================================
624 } /* namespace rtos */
625} /* namespace os */
626
627int*
628__errno (void);
629
644int*
646{
648}
649
654// ----------------------------------------------------------------------------
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:599
Interrupts critical section RAII helper.
Definition os-sched.h:524
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:247
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:74
int * __errno(void)
Per-thread error support.
Definition os-core.cpp:645
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:92
clock_systick sysclock
The system clock object instance.
class thread::stack * stack(void)
Get the interrupts stack.
Definition os-core.cpp:564
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1136
result_t initialize(void)
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:195
port::scheduler::state_t state_t
Type of variables holding scheduler state codes.
Definition os-decls.h:216
void start(void)
Start the RTOS scheduler.
Definition os-core.cpp:190
thread::threads_list & children_threads(thread *th)
Get the children threads.
Definition os-core.cpp:262
result_t initialize(void)
Initialise the RTOS scheduler.
Definition os-core.cpp:161
bool preemptive(void)
Check if the scheduler is in preemptive mode.
Definition os-sched.h:865
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:882
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition os-decls.h:236
uint64_t counter_t
Type of variables holding context switches counters.
Definition os-decls.h:231
int * __errno(void)
Implementation of the library __errno() function.
Definition os-thread.h:2095
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.
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:386