µ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-lists.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
19
20// ----------------------------------------------------------------------------
21
22#if defined(__clang__)
23#pragma clang diagnostic ignored "-Wc++98-compat"
24#endif
25
26// ----------------------------------------------------------------------------
27
28namespace os
29{
30 namespace rtos
31 {
32 namespace internal
33 {
34 // ======================================================================
35
36 void
38 {
39 // Add thread intrusive node at the end of the list.
40 insert_after (thread.child_links_,
41 const_cast<utils::static_double_list_links*> (tail ()));
42 }
43
44 // ======================================================================
45
46 void
48 {
49 if (head_.prev () == nullptr)
50 {
51 // If this is the first time, initialise the list to empty.
52 clear ();
53 }
54
55 thread::priority_t prio = node.thread_->priority ();
56
57 waiting_thread_node* after = static_cast<waiting_thread_node*> (
58 const_cast<utils::static_double_list_links*> (tail ()));
59
60 if (empty ())
61 {
62 // Insert at the end of the list.
63#if defined(OS_TRACE_RTOS_LISTS)
64 trace::printf ("ready %s() empty +%u\n", __func__, prio);
65#endif
66 }
67 else if (prio <= after->thread_->priority ())
68 {
69 // Insert at the end of the list.
70#if defined(OS_TRACE_RTOS_LISTS)
71 trace::printf ("ready %s() back %u +%u \n", __func__,
72 after->thread_->priority (), prio);
73#endif
74 }
75 else if (prio > head ()->thread_->priority ())
76 {
77#pragma GCC diagnostic push
78#if defined(__clang__)
79#elif defined(__GNUC__)
80#pragma GCC diagnostic ignored "-Wuseless-cast"
81#endif
82 // Insert at the beginning of the list.
83 after = static_cast<waiting_thread_node*> (
85#pragma GCC diagnostic pop
86
87#if defined(OS_TRACE_RTOS_LISTS)
88 trace::printf ("ready %s() front +%u %u \n", __func__, prio,
89 head ()->thread_->priority ());
90#endif
91 }
92 else
93 {
94#pragma GCC diagnostic push
95#if defined(__clang__)
96#elif defined(__GNUC__)
97#pragma GCC diagnostic ignored "-Wuseless-cast"
98#endif
99 // Insert in the middle of the list.
100 // The loop is guaranteed to terminate, and not hit the head.
101 // The weight is relatively small, priority() is not heavy.
102 while (prio > after->thread_->priority ())
103 {
104 after = static_cast<waiting_thread_node*> (
106 after->prev ()));
107 }
108#pragma GCC diagnostic pop
109
110#if defined(OS_TRACE_RTOS_LISTS)
111 trace::printf ("ready %s() middle %u +%u \n", __func__,
112 after->thread_->priority (), prio);
113#endif
114 }
115
116 insert_after (node, after);
117
118 node.thread_->state_ = thread::state::ready;
119 }
120
125 thread*
127 {
128 assert (!empty ());
129
130 thread* th = head ()->thread_;
131
132#if defined(OS_TRACE_RTOS_LISTS)
133 trace::printf ("ready %s() %p %s\n", __func__, th, th->name ());
134#endif
135
136 const_cast<waiting_thread_node*> (head ())->unlink ();
137
138 assert (th != nullptr);
139
140 // Unlinking is immediately followed by a context switch,
141 // so in order to guarantee that the thread is marked as
142 // running, it is saver to do it here.
143
144 th->state_ = thread::state::running;
145 return th;
146 }
147
148 // ======================================================================
149
193 void
195 {
196 thread::priority_t prio = node.thread_->priority ();
197
198 waiting_thread_node* after = static_cast<waiting_thread_node*> (
199 const_cast<utils::static_double_list_links*> (tail ()));
200
201 if (empty ())
202 {
203 // Insert at the end of the list.
204#if defined(OS_TRACE_RTOS_LISTS)
205 trace::printf ("wait %s() empty +%u\n", __func__, prio);
206#endif
207 }
208 else if (prio <= after->thread_->priority ())
209 {
210 // Insert at the end of the list.
211#if defined(OS_TRACE_RTOS_LISTS)
212 trace::printf ("wait %s() back %u +%u \n", __func__,
213 after->thread_->priority (), prio);
214#endif
215 }
216 else if (prio > head ()->thread_->priority ())
217 {
218#pragma GCC diagnostic push
219#if defined(__clang__)
220#elif defined(__GNUC__)
221#pragma GCC diagnostic ignored "-Wuseless-cast"
222#endif
223 // Insert at the beginning of the list.
224 after = static_cast<waiting_thread_node*> (
225 const_cast<utils::static_double_list_links*> (&head_));
226#pragma GCC diagnostic pop
227
228#if defined(OS_TRACE_RTOS_LISTS)
229 trace::printf ("wait %s() front +%u %u \n", __func__, prio,
230 head ()->thread_->priority ());
231#endif
232 }
233 else
234 {
235#pragma GCC diagnostic push
236#if defined(__clang__)
237#elif defined(__GNUC__)
238#pragma GCC diagnostic ignored "-Wuseless-cast"
239#endif
240 // Insert in the middle of the list.
241 // The loop is guaranteed to terminate, and not hit the head.
242 // The weight is relatively small, priority() is not heavy.
243 while (prio > after->thread_->priority ())
244 {
245 after = static_cast<waiting_thread_node*> (
247 after->prev ()));
248 }
249#pragma GCC diagnostic pop
250
251#if defined(OS_TRACE_RTOS_LISTS)
252 trace::printf ("wait %s() middle %u +%u \n", __func__,
253 after->thread_->priority (), prio);
254#endif
255 }
256
257 insert_after (node, after);
258 }
259
265 bool
267 {
268 thread* th;
269 {
270 // ----- Enter critical section -------------------------------------
272
273 // If the list is empty, silently return.
274 if (empty ())
275 {
276 return false;
277 }
278
279 // The top priority is to remove the entry from the list
280 // so that subsequent wakeups to address different threads.
281 th = head ()->thread_;
282 const_cast<waiting_thread_node*> (head ())->unlink ();
283 // ----- Exit critical section --------------------------------------
284 }
285 assert (th != nullptr);
286
287 thread::state_t state = th->state ();
288 if (state != thread::state::destroyed)
289 {
290 th->resume ();
291 }
292 else
293 {
294#if defined(OS_TRACE_RTOS_LISTS)
295 trace::printf ("%s() gone \n", __func__);
296#endif
297 }
298
299 return true;
300 }
301
302 void
304 {
305 while (resume_one ())
306 ;
307 }
308
309 // ======================================================================
310
312 {
313#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
314 trace::printf ("%s() %p \n", __func__, this);
315#endif
316 }
317
319 {
320#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
321 trace::printf ("%s() %p \n", __func__, this);
322#endif
323 }
324
325 // ======================================================================
326
328 rtos::thread& th)
329 : timestamp_node{ ts }, //
330 thread (th)
331 {
332#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
333 trace::printf ("%s() %p \n", __func__, this);
334#endif
335 }
336
338 {
339#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
340 trace::printf ("%s() %p \n", __func__, this);
341#endif
342 }
343
344 // Must be called in a critical section.
345 void
347 {
348 rtos::thread* th = &this->thread;
349 this->unlink ();
350
351 thread::state_t state = th->state ();
352 if (state != thread::state::destroyed)
353 {
354 th->resume ();
355 }
356 }
357
358 // ======================================================================
359
360#if !defined(OS_USE_RTOS_PORT_TIMER)
361
363 : timestamp_node{ ts }, //
364 tmr (tm)
365 {
366#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
367 trace::printf ("%s() %p \n", __func__, this);
368#endif
369 }
370
372 {
373#if defined(OS_TRACE_RTOS_LISTS_CONSTRUCT)
374 trace::printf ("%s() %p \n", __func__, this);
375#endif
376 }
377
382 void
384 {
385 this->unlink ();
386 tmr.internal_interrupt_service_routine ();
387 }
388
389#endif
390
391 // ======================================================================
392
407#pragma GCC diagnostic push
408#if defined(__clang__)
409#elif defined(__GNUC__)
410#pragma GCC diagnostic ignored "-Wnull-dereference"
411#endif
412 void
414 {
415 clock::timestamp_t timestamp = node.timestamp;
416
417 timeout_thread_node* after = static_cast<timeout_thread_node*> (
418 const_cast<utils::static_double_list_links*> (tail ()));
419
420 if (empty ())
421 {
422 // Insert at the end of the list.
423#if defined(OS_TRACE_RTOS_LISTS_CLOCKS)
424 trace::printf ("clock %s() empty +%u\n", __func__,
425 static_cast<uint32_t> (timestamp));
426#endif
427 }
428 else if (timestamp >= after->timestamp)
429 {
430 // Insert at the end of the list.
431#if defined(OS_TRACE_RTOS_LISTS_CLOCKS)
432 trace::printf ("clock %s() back %u +%u\n", __func__,
433 static_cast<uint32_t> (after->timestamp),
434 static_cast<uint32_t> (timestamp));
435#endif
436 }
437 else if (timestamp < head ()->timestamp)
438 {
439#pragma GCC diagnostic push
440#if defined(__clang__)
441#elif defined(__GNUC__)
442#pragma GCC diagnostic ignored "-Wuseless-cast"
443#endif
444 // Insert at the beginning of the list
445 // and update the new head.
446 after = static_cast<timeout_thread_node*> (
447 const_cast<utils::static_double_list_links*> (&head_));
448#if defined(OS_TRACE_RTOS_LISTS_CLOCKS)
449 trace::printf ("clock %s() front +%u %u\n", __func__,
450 static_cast<uint32_t> (timestamp),
451 static_cast<uint32_t> (head ()->timestamp));
452#endif
453#pragma GCC diagnostic pop
454 }
455 else
456 {
457 // Insert in the middle of the list.
458 // The loop is guaranteed to terminate.
459 while (timestamp < after->timestamp)
460 {
461#pragma GCC diagnostic push
462#if defined(__clang__)
463#elif defined(__GNUC__)
464#pragma GCC diagnostic ignored "-Wuseless-cast"
465#endif
466 after = static_cast<timeout_thread_node*> (
468 after->prev ()));
469 }
470#if defined(OS_TRACE_RTOS_LISTS_CLOCKS)
471 trace::printf ("clock %s() middle %u +%u\n", __func__,
472 static_cast<uint32_t> (after->timestamp),
473 static_cast<uint32_t> (timestamp));
474#endif
475#pragma GCC diagnostic pop
476 }
477
478 insert_after (node, after);
479 }
480#pragma GCC diagnostic pop
481
489 void
491 {
492 if (head_.next () == nullptr)
493 {
494 // This happens before the constructors are executed.
495 return;
496 }
497
498 // Multiple threads can wait for the same time stamp, so
499 // iterate until a node with future time stamp is identified.
500 for (;;)
501 {
502 // ----- Enter critical section -----------------------------------
504
505 if (empty ())
506 {
507 break;
508 }
509#pragma GCC diagnostic push
510#if defined(__clang__)
511#elif defined(__GNUC__)
512#pragma GCC diagnostic ignored "-Wnull-dereference"
513#endif
514 clock::timestamp_t head_ts = head ()->timestamp;
515#pragma GCC diagnostic pop
516 if (now >= head_ts)
517 {
518#if defined(OS_TRACE_RTOS_LISTS_CLOCKS)
519 trace::printf ("%s() %u \n", __func__,
520 static_cast<uint32_t> (sysclock.now ()));
521#endif
522 const_cast<timestamp_node*> (head ())->action ();
523 }
524 else
525 {
526 break;
527 }
528 // ----- Exit critical section ------------------------------------
529 }
530 }
531
532 // ======================================================================
533
534 void
536 {
537 if (head_.prev () == nullptr)
538 {
539 // If this is the first time, initialise the list to empty.
540 clear ();
541 }
542
543 waiting_thread_node* after = static_cast<waiting_thread_node*> (
544 const_cast<utils::static_double_list_links*> (tail ()));
545
546#if defined(OS_TRACE_RTOS_THREAD)
547 trace::printf ("terminated %s() %p %s\n", __func__, &node.thread_,
548 node.thread_->name ());
549#endif
550
551 node.thread_->state_ = thread::state::terminated;
552
553 insert_after (node, after);
554 }
555
556 // ----------------------------------------------------------------------
557 } /* namespace internal */
558 } /* namespace rtos */
559} /* namespace os */
560
561// ----------------------------------------------------------------------------
virtual timestamp_t now(void)
Tell the current time, possibly adjusted for epoch.
void check_timestamp(port::clock::timestamp_t now)
Check list time stamps.
Definition os-lists.cpp:490
volatile timestamp_node * head(void) const
Get list head.
Definition os-lists.h:966
void link(timestamp_node &node)
Add a new thread node to the list.
Definition os-lists.cpp:413
const char * name(void) const
Get object name.
Definition os-decls.h:753
thread * unlink_head(void)
Remove the top node from the list.
Definition os-lists.cpp:126
volatile waiting_thread_node * head(void) const
Get list head.
Definition os-lists.h:904
void link(waiting_thread_node &node)
Add a new thread node to the list.
Definition os-lists.cpp:47
void link(waiting_thread_node &node)
Add a new thread node to the list.
Definition os-lists.cpp:535
void link(thread &thread)
Add a new thread node to the list.
Definition os-lists.cpp:37
Double linked list node, with time stamp and thread.
Definition os-lists.h:220
timeout_thread_node(port::clock::timestamp_t ts, thread &th)
Construct a clock timeout node.
Definition os-lists.cpp:327
rtos::thread & thread
Reference to thread who initiated the timeout.
Definition os-lists.h:289
virtual ~timeout_thread_node() override
Destruct the node.
Definition os-lists.cpp:337
virtual void action(void) override
Action to perform when the time stamp is reached.
Definition os-lists.cpp:346
timer & tmr
Reference to waiting timer.
Definition os-lists.h:378
virtual void action(void) override
Action to perform when the time stamp is reached.
Definition os-lists.cpp:383
timer_node(port::clock::timestamp_t ts, timer &tm)
Construct a clock timer node.
Definition os-lists.cpp:362
virtual ~timer_node() override
Destruct the node.
Definition os-lists.cpp:371
Double linked list node, with time stamp.
Definition os-lists.h:129
port::clock::timestamp_t timestamp
Time stamp when the next action will be performed.
Definition os-lists.h:198
virtual ~timestamp_node()
Destruct the node.
Definition os-lists.cpp:318
timestamp_node(port::clock::timestamp_t ts)
Construct a node with a time stamp.
Definition os-lists.cpp:311
Double linked list node, with thread reference.
Definition os-lists.h:59
rtos::thread * thread_
Pointer to waiting thread.
Definition os-lists.h:107
void link(waiting_thread_node &node)
Add a new thread node to the list.
Definition os-lists.cpp:194
bool resume_one(void)
Wake-up one thread (the oldest with the highest priority)
Definition os-lists.cpp:266
volatile waiting_thread_node * head(void) const
Get list head.
Definition os-lists.h:925
void resume_all(void)
Wake-up all threads in the list.
Definition os-lists.cpp:303
Interrupts critical section RAII helper.
Definition os-sched.h:502
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:251
uint8_t state_t
Type of variables holding thread states.
Definition os-thread.h:357
result_t priority(priority_t prio)
Set the assigned scheduling priority.
void resume(void)
Resume the thread.
state_t state(void) const
Get thread scheduler state.
Definition os-thread.h:2355
User single-shot or periodic timer.
Definition os-timer.h:56
static_double_list_links head_
A list node used to point to head and tail.
Definition lists.h:473
void insert_after(static_double_list_links &node, static_double_list_links *after)
Insert a new node after existing node.
Definition lists.cpp:121
bool empty(void) const
Check if the list is empty.
Definition lists.h:1001
void clear(void)
Clear the list.
Definition lists.cpp:108
volatile static_double_list_links * tail(void) const
Get the list tail.
Definition lists.h:1014
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:59
int unlink(const char *name)
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.
uint8_t priority_t
Type of variables holding thread priorities.
Definition os-thread.h:271
System namespace.
Single file µOS++ RTOS definitions.
@ running
Has the CPU and runs.
Definition os-thread.h:386
@ destroyed
Terminated and resources (like stack) released.
Definition os-thread.h:398
@ terminated
No longer usable, but resources not yet released.
Definition os-thread.h:394
@ ready
Present in the READY list and competing for CPU.
Definition os-thread.h:382