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