µ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-thread.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#include <memory>
20#include <stdexcept>
21
22// ----------------------------------------------------------------------------
23
24#if defined(__clang__)
25#pragma clang diagnostic ignored "-Wc++98-compat"
26#endif
27
28// ----------------------------------------------------------------------------
29
30namespace os
31{
32 namespace rtos
33 {
34 // ------------------------------------------------------------------------
35
40 std::size_t thread::stack::min_size_bytes_ = port::stack::min_size_bytes;
41
42 std::size_t thread::stack::default_size_bytes_ =
43 port::stack::default_size_bytes;
44
49 // ------------------------------------------------------------------------
50 using mutexes_list = utils::intrusive_list<
51 mutex, utils::double_list_links, &mutex::owner_links_>;
52
53 // ========================================================================
101 const thread::attributes thread::initializer;
102
152 void
154 {
155 // Align the bottom of the stack.
156 void* pa = bottom_address_;
157 bottom_address_ = static_cast<stack::element_t*> (std::align (
159 size_bytes_));
160
161 // If there is not enough space for the minimal stack, fail.
162 os_assert_throw(bottom_address_ != nullptr, ENOMEM);
163
164 element_t* p = bottom_address_;
165 element_t* pend = top ();
166
167 // Initialise the entire stack with the magic word.
168 for (; p < pend; ++p)
169 {
170 *p = magic;
171 }
172
173 // Compute the actual size. The -1 is to leave space for the magic.
174 size_bytes_ = ((static_cast<std::size_t> (p - bottom_address_) - 1)
175 * sizeof(element_t));
176 }
177
190 std::size_t
192 {
193 element_t* p = bottom_address_;
194 std::size_t count = 0;
195 while (*p == magic)
196 {
197 count += sizeof(element_t);
198 ++p;
199 }
200
201 return count;
202 }
203
216 void
217 thread::internal_invoke_with_exit_ (thread* thread)
218 {
219#if defined(OS_TRACE_RTOS_THREAD)
220 trace::printf ("%s() @%p %s\n", __func__, thread, thread->name ());
221#endif
222
223 void* exit_ptr;
224#if defined(__EXCEPTIONS)
225 try
226 {
227 exit_ptr = thread->func_ (thread->func_args_);
228 }
229 catch (std::exception const &e)
230 {
231 trace::printf ("%s() @%p %s top exception \"%s\"\n", __func__,
232 thread, thread->name (), e.what ());
233 exit_ptr = nullptr;
234 }
235 catch (...)
236 {
237 trace::printf ("%s() @%p %s top exception\n", __func__, thread,
238 thread->name ());
239 exit_ptr = nullptr;
240 }
241#else
242 exit_ptr = thread->func_ (thread->func_args_);
243#endif
244 thread->internal_exit_ (exit_ptr);
245 }
246
248 {
249#if defined(OS_TRACE_RTOS_THREAD)
250 trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
251#endif
252 // Must be explicit here, since they are not done in the members
253 // declarations to allow th_enable_assert_reuse.
254 state_ = state::initializing;
255 func_ = nullptr;
256 }
257
258 thread::thread (const char* name) :
260 { name }
261 {
262#if defined(OS_TRACE_RTOS_THREAD)
263 trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
264#endif
265 // Must be explicit here, since they are not done in the members
266 // declarations to allow th_enable_assert_reuse.
267 state_ = state::initializing;
268 }
269
292 bool
294 {
295 return ((thread.state_ == state::ready ||
296 thread.state_ == state::running ||
297 thread.state_ == state::suspended ||
298 thread.state_ == state::terminated));
299 }
300
345 thread::thread (func_t function, func_args_t args, const attributes& attr,
346 const allocator_type& allocator) :
347 thread
348 { nullptr, function, args, attr, allocator }
349 {
350 }
351
396 thread::thread (const char* name, func_t function, func_args_t args,
397 const attributes& attr, const allocator_type& allocator) :
398 object_named_system
399 { name }
400 {
401#if defined(OS_TRACE_RTOS_THREAD)
402 trace::printf ("%s() @%p %s\n", __func__, this, this->name ());
403#endif
404
405#if defined(DEBUG)
406 if (attr.th_enable_assert_reuse) {
407 // Expect either statically initialised (undefined), or destroyed.
408 assert((state_ == state::undefined) || (state_ == state::destroyed));
409 }
410#endif /* DEBUG */
411
412 state_ = state::initializing;
413
414 allocator_ = &allocator;
415
416 if (attr.th_stack_address != nullptr
417 && attr.th_stack_size_bytes > stack::min_size ())
418 {
419 internal_construct_ (function, args, attr, nullptr, 0);
420 }
421 else
422 {
423 using allocator_type2 = memory::allocator<stack::allocation_element_t>;
424
425 if (attr.th_stack_size_bytes > stack::min_size ())
426 {
427 allocated_stack_size_elements_ = (attr.th_stack_size_bytes
428 + sizeof(stack::allocation_element_t) - 1)
429 / sizeof(stack::allocation_element_t);
430 }
431 else
432 {
433 allocated_stack_size_elements_ = (stack::default_size ()
434 + sizeof(stack::allocation_element_t) - 1)
435 / sizeof(stack::allocation_element_t);
436 }
437
438#pragma GCC diagnostic push
439#if defined(__clang__)
440#elif defined(__GNUC__)
441#pragma GCC diagnostic ignored "-Wuseless-cast"
442#endif
443 allocated_stack_address_ =
444 reinterpret_cast<stack::element_t*> (const_cast<allocator_type2&> (allocator).allocate (
445 allocated_stack_size_elements_));
446#pragma GCC diagnostic pop
447
448 // Stack allocation failed.
449 assert(allocated_stack_address_ != nullptr);
450
451 internal_construct_ (
452 function,
453 args,
454 attr,
455 allocated_stack_address_,
456 allocated_stack_size_elements_
457 * sizeof(stack::allocation_element_t));
458 }
459 }
460
465 void
466 thread::internal_construct_ (func_t function, func_args_t args,
467 const attributes& attr, void* stack_address,
468 std::size_t stack_size_bytes)
469 {
470 // Don't call this from interrupt handlers.
472
473 // The thread function must be real.
474 assert(function != nullptr);
475 // Don't forget to set the thread priority.
476 assert(attr.th_priority != priority::none);
477
478 clock_ = attr.clock != nullptr ? attr.clock : &sysclock;
479
480 if (stack_address != nullptr)
481 {
482 // The attributes should not define any storage in this case.
483 if (attr.th_stack_size_bytes > stack::min_size ())
484 {
485 // The stack address must be real.
486 assert(attr.th_stack_address == nullptr);
487 }
488
489 stack ().set (static_cast<stack::element_t*> (stack_address),
490 stack_size_bytes);
491 }
492 else
493 {
494 stack ().set (static_cast<stack::element_t*> (attr.th_stack_address),
495 attr.th_stack_size_bytes);
496 }
497
498#if defined(OS_TRACE_RTOS_THREAD)
499 trace::printf ("%s() @%p %s p%u stack{%p,%u}\n", __func__, this, name (),
500 attr.th_priority, stack ().bottom_address_,
501 stack ().size_bytes_);
502#endif
503
504 {
505 // Prevent the new thread to execute before all members are set.
506 // ----- Enter critical section -------------------------------------
507 scheduler::critical_section scs;
508
509 // Get attributes from user structure.
510 prio_assigned_ = attr.th_priority;
511
512 func_ = function;
513 func_args_ = args;
514
515 parent_ = this_thread::_thread ();
516 if (scheduler::started () && (parent_ != nullptr))
517 {
518 parent_->children_.link (*this);
519 }
520 else
521 {
522 scheduler::top_threads_list_.link (*this);
523 }
524
525 stack ().initialize ();
526
527#if defined(OS_USE_RTOS_PORT_SCHEDULER)
528
529 port::thread::create (this);
530 state_ = state::ready;
531
532#else
533
534#pragma GCC diagnostic push
535#if defined(__clang__)
536#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
537#endif
538 // Create the port specific context.
540 &context_, reinterpret_cast<void*> (internal_invoke_with_exit_),
541 this);
542#pragma GCC diagnostic pop
543
544 if (!scheduler::started ())
545 {
546 scheduler::current_thread_ = this;
547 }
548
549 // Add to ready list, but do not yield yet.
550 resume ();
551
552#endif
553 // ----- Exit critical section --------------------------------------
554 }
555 // For just in case the new thread has higher priority.
557 }
558
578 {
579#if defined(OS_TRACE_RTOS_THREAD)
580 trace::printf ("%s() @%p %s \n", __func__, this, name ());
581#endif
582
583 // Prevent the main thread to destroy itself while running
584 // the exit cleanup code.
585 if (this != &this_thread::thread ())
586 {
587 // Extra test to avoid the 'already gone' message.
588 if (state_ != state::destroyed)
589 {
590 kill ();
591 }
592 }
593 else
594 {
595#if defined(OS_TRACE_RTOS_THREAD)
596 trace::printf ("%s() @%p %s nop, cannot commit suicide\n", __func__,
597 this, name ());
598#endif
599 }
600 }
601
611 void
613 {
614#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
615 trace::printf ("%s() @%p %s %u\n", __func__, this, name (),
616 prio_assigned_);
617#endif
618
619#if defined(OS_USE_RTOS_PORT_SCHEDULER)
620
621 {
622 // ----- Enter critical section -------------------------------------
624
625 state_ = state::ready;
626 port::thread::resume (this);
627 // ----- Exit critical section --------------------------------------
628 }
629
630#else
631
632 // Don't call this from high priority interrupts.
633 assert(port::interrupts::is_priority_valid ());
634
635 {
636 // ----- Enter critical section -------------------------------------
638
639 // If the thread is not already in the ready list, enqueue it.
640 if (ready_node_.next () == nullptr)
641 {
642 scheduler::ready_threads_list_.link (ready_node_);
643 // state::ready set in above link().
644 }
645 // ----- Exit critical section --------------------------------------
646 }
647
649
650#endif
651
652 }
653
662 {
663 // trace::printf ("%s() @%p %s\n", __func__, this, name ());
664
665 if (prio_inherited_ == priority::none)
666 {
667 // The common case is to have no inherited priority;
668 // return the assigned one.
669 return prio_assigned_;
670 }
671 else
672 {
673 // Return the maximum between inherited and assigned.
674 return
675 (prio_inherited_ >= prio_assigned_) ?
676 prio_inherited_ : prio_assigned_;
677 }
678 }
679
688 {
689 // Don't call this from interrupt handlers.
691
692 return prio_inherited_;
693 }
694
716 {
717#if defined(OS_TRACE_RTOS_THREAD)
718 trace::printf ("%s(%u) @%p %s\n", __func__, prio, this, name ());
719#endif
720
721 // Don't call this from interrupt handlers.
723 // Check the priority, it is not in the allowed range.
724 os_assert_err(prio < priority::error, EINVAL);
725 os_assert_err(prio != priority::none, EINVAL);
726
727 if (prio_assigned_ == prio)
728 {
729 // Optimise, if priority did not change.
730 return result::ok;
731 }
732
733 prio_assigned_ = prio;
734
735 result_t res = result::ok;
736
737#if defined(OS_USE_RTOS_PORT_SCHEDULER)
738
739 // The port must perform a context switch.
740 res = port::thread::priority (this, prio);
741
742#else
743
744 if (state_ == state::ready)
745 {
746 // ----- Enter critical section -------------------------------------
748
749 // Remove from initial location and reinsert according
750 // to new priority.
751 ready_node_.unlink ();
752 scheduler::ready_threads_list_.link (ready_node_);
753 // ----- Exit critical section --------------------------------------
754 }
755
756 // Mandatory, the priority might have been raised, the
757 // task must be scheduled to run.
759
760#endif
761
762 return res;
763 }
764
784 {
785#if defined(OS_TRACE_RTOS_THREAD)
786 trace::printf ("%s(%u) @%p %s\n", __func__, prio, this, name ());
787#endif
788
789 // Don't call this from interrupt handlers.
791 // Check the priority, it is not in the allowed range.
792 os_assert_err(prio < priority::error, EINVAL);
793
794 // Warning: do not check for `priority::none`, since
795 // `mutex::unlock()` sets it when the list of mutexes owned
796 // by a thread is empty.
797
798 if (prio == prio_inherited_)
799 {
800 // Optimise, if priority did not change.
801 return result::ok;
802 }
803
804 prio_inherited_ = prio;
805
806 if (prio_inherited_ < prio_assigned_)
807 {
808 // Optimise, no need to reschedule.
809 return result::ok;
810 }
811
812 result_t res = result::ok;
813
814#if defined(OS_USE_RTOS_PORT_SCHEDULER)
815
816 // The port must perform a context switch.
817 res = port::thread::priority (this, prio);
818
819#else
820
821 if (state_ == state::ready)
822 {
823 // ----- Enter critical section -------------------------------------
825
826 // Remove from initial location and reinsert according
827 // to new priority.
828 ready_node_.unlink ();
829 scheduler::ready_threads_list_.link (ready_node_);
830 // ----- Exit critical section --------------------------------------
831 }
832
833 // Mandatory, the priority might have been raised, the
834 // task must be scheduled to run.
836
837#endif
838
839 return res;
840 }
841
862 {
863#if defined(OS_TRACE_RTOS_THREAD)
864 trace::printf ("%s() @%p %s\n", __func__, this, name ());
865#endif
866
867 // Don't call this from interrupt handlers.
869
870#if defined(OS_USE_RTOS_PORT_SCHEDULER)
871
872 result_t res = port::thread::detach (this);
873 if (res != result::ok)
874 {
875 return res;
876 }
877
878#else
879
880 // TODO: implement
881
882#endif
883
884 return result::ok;
885 }
886
916 thread::join (void** exit_ptr)
917 {
918#if defined(OS_TRACE_RTOS_THREAD)
919 trace::printf ("%s() @%p %s\n", __func__, this, name ());
920#endif
921
922 // Don't call this from interrupt handlers.
924 // Don't call this from critical regions.
926
927 // Fail if current thread
928 assert(this != this_thread::_thread ());
929
930 while (state_ != state::destroyed)
931 {
932 joiner_ = this_thread::_thread ();
933 this_thread::_thread ()->internal_suspend_ ();
934 }
935
936#if defined(OS_TRACE_RTOS_THREAD)
937 trace::printf ("%s() @%p %s joined\n", __func__, this, name ());
938#endif
939
940 if (exit_ptr != nullptr)
941 {
942 *exit_ptr = func_result_;
943 }
944
945 return result::ok;
946 }
947
968 {
969#if defined(OS_TRACE_RTOS_THREAD)
970 trace::printf ("%s() @%p %s\n", __func__, this, name ());
971#endif
972
973 // Don't call this from interrupt handlers.
975
976 // TODO: implement according to POSIX specs.
977 return result::ok;
978 }
979
991 bool
992 thread::interrupt (bool interrupt)
993 {
994#if defined(OS_TRACE_RTOS_THREAD)
995 trace::printf ("%s() @%p %s\n", __func__, this, name ());
996#endif
997
998 bool tmp = interrupted_;
999 interrupted_ = interrupt;
1000
1001 resume ();
1002 return tmp;
1003 }
1004
1013 void
1014 thread::internal_suspend_ (void)
1015 {
1016#if defined(OS_TRACE_RTOS_THREAD)
1017 trace::printf ("%s() @%p %s\n", __func__, this, name ());
1018#endif
1019
1020 {
1021 // ----- Enter critical section -------------------------------------
1023
1024 // Remove this thread from the ready list, if there.
1026
1027 state_ = state::suspended;
1028 // ----- Exit critical section --------------------------------------
1029 }
1030
1032 }
1033
1034 void
1035 thread::internal_exit_ (void* exit_ptr)
1036 {
1037#if defined(OS_TRACE_RTOS_THREAD)
1038 trace::printf ("%s() @%p %s\n", __func__, this, name ());
1039#endif
1040
1041 // Don't call this from interrupt handlers.
1042 assert(!interrupts::in_handler_mode ());
1043
1044 {
1045 // ----- Enter critical section -------------------------------------
1046 scheduler::critical_section scs;
1047
1048 {
1049 // ----- Enter critical section ---------------------------------
1050 interrupts::critical_section ics;
1051
1052 ready_node_.unlink ();
1053
1054 child_links_.unlink ();
1055 // ----- Exit critical section ----------------------------------
1056 }
1057
1058 // There must be no children threads still alive.
1059 assert(children_.empty ());
1060 parent_ = nullptr;
1061
1062 func_ = nullptr;
1063 func_args_ = nullptr;
1064
1065 // There must be no more mutexes locked by this thread.
1066 assert(mutexes_.empty ());
1067 assert(acquired_mutexes_ == 0);
1068
1069 func_result_ = exit_ptr;
1070 // ----- Exit critical section --------------------------------------
1071 }
1072
1073 {
1074 // ----- Enter critical section -------------------------------------
1075 interrupts::critical_section ics;
1076
1077 // Add to a list of threads to be destroyed by the idle thread.
1078 // Also set state::terminated.
1079 scheduler::terminated_threads_list_.link (ready_node_);
1080 // ----- Exit critical section --------------------------------------
1081 }
1082
1083#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1084
1085 port::thread::destroy_this (this);
1086 // Does not return if the current thread.
1087
1088#else
1089
1090 // At this point, since the thread state is no longer 'running',
1091 // the thread is no longer linked in the READY list.
1093
1094#endif
1095
1096 assert(true);
1097 while (true)
1098 ;
1099
1100 // Definitely does not return.
1101 }
1102
1103 void
1104 thread::internal_check_stack_ (void)
1105 {
1106 if (stack ().size () > 0)
1107 {
1108 if (!stack ().check_bottom_magic () || !stack ().check_top_magic ())
1109 {
1110 trace::printf("%s() @%p %s\n", __func__, this, name ());
1111 assert(stack ().check_bottom_magic ());
1112 assert(stack ().check_top_magic ());
1113 }
1114
1115#if defined(OS_TRACE_RTOS_THREAD)
1116 trace::printf ("%s() @%p %s stack: %u/%u bytes used\n", __func__,
1117 this, name (),
1118 stack ().size () - stack ().available (),
1119 stack ().size ());
1120#endif
1121
1122 // Clear stack to avoid further checks
1123 stack ().clear ();
1124 }
1125 }
1126
1127#pragma GCC diagnostic push
1128#if defined(__clang__)
1129#elif defined(__GNUC__)
1130#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
1131#endif
1132 // Called from kill() and from idle thread.
1133 void
1134 thread::internal_destroy_ (void)
1135 {
1136#if defined(OS_TRACE_RTOS_THREAD)
1137 trace::printf ("%s() @%p %s\n", __func__, this, name ());
1138#endif
1139
1140 internal_check_stack_ ();
1141
1142 if (allocated_stack_address_ != nullptr)
1143 {
1144 typedef typename std::allocator_traits<allocator_type>::pointer pointer;
1145
1146#pragma GCC diagnostic push
1147#if defined(__clang__)
1148#elif defined(__GNUC__)
1149#pragma GCC diagnostic ignored "-Wuseless-cast"
1150#pragma GCC diagnostic ignored "-Wcast-align"
1151#endif
1152 static_cast<allocator_type*> (const_cast<void*> (allocator_))->deallocate (
1153 reinterpret_cast<pointer> (allocated_stack_address_),
1154 allocated_stack_size_elements_);
1155#pragma GCC diagnostic pop
1156
1157 allocated_stack_address_ = nullptr;
1158 }
1159
1160 {
1161 // ----- Enter critical section -------------------------------------
1162 scheduler::critical_section scs;
1163
1164 mutexes_list& mx_list = reinterpret_cast<mutexes_list&> (mutexes_);
1165 while (not mx_list.empty ())
1166 {
1167 auto* mx = mx_list.unlink_head ();
1168
1169 mx->internal_mark_owner_dead_ ();
1170
1171 // Unlock the mutex as owned by the thread itself.
1172 mx->internal_unlock_ (this);
1173 }
1174 // ----- Exit critical section --------------------------------------
1175 }
1176
1177 state_ = state::destroyed;
1178
1179 if (joiner_ != nullptr)
1180 {
1181 joiner_->resume ();
1182 }
1183 }
1184#pragma GCC diagnostic pop
1185
1198 result_t
1200 {
1201#if defined(OS_TRACE_RTOS_THREAD)
1202 trace::printf ("%s() @%p %s\n", __func__, this, name ());
1203#endif
1204
1205 // Don't call this from interrupt handlers.
1207
1208 {
1209 // ----- Enter critical section -------------------------------------
1211
1212 if (state_ == state::destroyed)
1213 {
1214#if defined(OS_TRACE_RTOS_THREAD)
1215 trace::printf ("%s() @%p %s already gone\n", __func__, this,
1216 name ());
1217#endif
1218 return result::ok; // Already exited itself
1219 }
1220
1221 {
1222 // ----- Enter critical section ---------------------------------
1224
1225 // Remove thread from the funeral list and kill it here.
1226 ready_node_.unlink ();
1227
1228 // If the thread is waiting on an event, remove it from the list.
1229 if (waiting_node_ != nullptr)
1230 {
1231 waiting_node_->unlink ();
1232 }
1233
1234 // If the thread is waiting on a timeout, remove it from the list.
1235 if (clock_node_ != nullptr)
1236 {
1237 clock_node_->unlink ();
1238 }
1239
1240 child_links_.unlink ();
1241 // ----- Exit critical section ----------------------------------
1242 }
1243
1244 // The must be no more children threads alive.
1245 assert(children_.empty ());
1246 parent_ = nullptr;
1247
1248#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1249
1250 port::thread::destroy_other (this);
1251
1252#endif
1253
1254 func_result_ = nullptr;
1255
1256 func_ = nullptr;
1257 func_args_ = nullptr;
1258
1259 internal_destroy_ ();
1260
1261 // There must be no mutexes locked by this thread.
1262 // Must have been cleaned before.
1263 assert(mutexes_.empty ());
1264 assert(acquired_mutexes_ == 0);
1265
1266 // ----- Exit critical section --------------------------------------
1267 }
1268
1269 return result::ok;
1270 }
1271
1280 result_t
1282 {
1283#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1284 trace::printf ("%s(0x%X) @%p %s <0x%X\n", __func__, mask, this, name (),
1285 event_flags_.mask ());
1286#endif
1287
1288 result_t res = event_flags_.raise (mask, oflags);
1289
1290 this->resume ();
1291
1292#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1293 trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
1294 event_flags_.mask ());
1295#endif
1296
1297 return res;
1298 }
1299
1304 result_t
1305 thread::internal_flags_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1306 flags::mode_t mode)
1307 {
1308#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1309 trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
1310 name (), event_flags_.mask ());
1311#endif
1312
1313 // Don't call this from interrupt handlers.
1315 // Don't call this from critical regions.
1316 os_assert_err(!scheduler::locked (), EPERM);
1317
1318 {
1319 // ----- Enter critical section ---------------------------------
1321
1322 if (event_flags_.check_raised (mask, oflags, mode))
1323 {
1324#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1325 trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1326 this, name (), event_flags_.mask ());
1327#endif
1328 return result::ok;
1329 }
1330 // ----- Exit critical section ----------------------------------
1331 }
1332
1333#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1334 clock::timestamp_t begin_timestamp = clock_->now ();
1335#endif
1336 for (;;)
1337 {
1338 {
1339 // ----- Enter critical section ---------------------------------
1340 interrupts::critical_section ics;
1341
1342 if (event_flags_.check_raised (mask, oflags, mode))
1343 {
1344#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1345 clock::duration_t slept_ticks =
1346 static_cast<clock::duration_t> (clock_->now ()
1347 - begin_timestamp);
1348 trace::printf ("%s(0x%X,%u) in %d @%p %s >0x%X\n", __func__,
1349 mask, mode, slept_ticks, this, name (),
1350 event_flags_.mask ());
1351#endif
1352 return result::ok;
1353 }
1354 // ----- Exit critical section ----------------------------------
1355 }
1356
1357 internal_suspend_ ();
1358
1359 if (interrupted ())
1360 {
1361#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1362 trace::printf ("%s(0x%X,%u) EINTR @%p %s\n", __func__, mask, mode,
1363 this, name ());
1364#endif
1365 return EINTR;
1366 }
1367 }
1368
1369 /* NOTREACHED */
1370 return ENOTRECOVERABLE;
1371 }
1372
1373 result_t
1374 thread::internal_flags_try_wait_ (flags::mask_t mask, flags::mask_t* oflags,
1375 flags::mode_t mode)
1376 {
1377#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1378 trace::printf ("%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode, this,
1379 name (), event_flags_.mask ());
1380#endif
1381
1382 // Don't call this from interrupt handlers.
1384
1385 {
1386 // ----- Enter critical section -------------------------------------
1387 interrupts::critical_section ics;
1388
1389 if (event_flags_.check_raised (mask, oflags, mode))
1390 {
1391#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1392 trace::printf ("%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1393 this, name (), event_flags_.mask ());
1394#endif
1395 return result::ok;
1396 }
1397 else
1398 {
1399#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1400 trace::printf ("%s(0x%X,%u) EWOULDBLOCK @%p %s \n", __func__,
1401 mask, mode, this, name ());
1402#endif
1403 return EWOULDBLOCK;
1404 }
1405 // ----- Exit critical section --------------------------------------
1406 }
1407 }
1408
1409 result_t
1410 thread::internal_flags_timed_wait_ (flags::mask_t mask,
1411 clock::duration_t timeout,
1412 flags::mask_t* oflags,
1413 flags::mode_t mode)
1414 {
1415#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1416 trace::printf ("%s(0x%X,%u,%u) @%p %s <0x%X\n", __func__, mask, timeout,
1417 mode, this, name (), event_flags_.mask ());
1418#endif
1419
1420 // Don't call this from interrupt handlers.
1422 // Don't call this from critical regions.
1423 os_assert_err(!scheduler::locked (), EPERM);
1424
1425 {
1426 // ----- Enter critical section -------------------------------------
1427 interrupts::critical_section ics;
1428
1429 if (event_flags_.check_raised (mask, oflags, mode))
1430 {
1431#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1432 trace::printf ("%s(0x%X,%u,%u) @%p %s >0x%X\n", __func__, mask,
1433 timeout, mode, this, name (),
1434 event_flags_.mask ());
1435#endif
1436 return result::ok;
1437 }
1438 // ----- Exit critical section --------------------------------------
1439 }
1440
1441 internal::clock_timestamps_list& clock_list = clock_->steady_list ();
1442 clock::timestamp_t timeout_timestamp = clock_->steady_now () + timeout;
1443
1444#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1445 clock::timestamp_t begin_timestamp = clock_->steady_now ();
1446#endif
1447
1448 // Prepare a timeout node pointing to the current thread.
1449 internal::timeout_thread_node timeout_node
1450 { timeout_timestamp, *this };
1451
1452 for (;;)
1453 {
1454 {
1455 // ----- Enter critical section ---------------------------------
1456 interrupts::critical_section ics;
1457
1458 if (event_flags_.check_raised (mask, oflags, mode))
1459 {
1460#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1461 clock::duration_t slept_ticks =
1462 static_cast<clock::duration_t> (clock_->steady_now ()
1463 - begin_timestamp);
1464#pragma GCC diagnostic push
1465#if defined(__clang__)
1466#elif defined(__GNUC__)
1467#pragma GCC diagnostic ignored "-Wuseless-cast"
1468#endif
1469 trace::printf ("%s(0x%X,%u,%u) in %u @%p %s >0x%X\n",
1470 __func__, mask, timeout, mode,
1471 static_cast<unsigned int> (slept_ticks), this,
1472 name (), event_flags_.mask ());
1473#pragma GCC diagnostic pop
1474#endif
1475 return result::ok;
1476 }
1477
1478 // Remove this thread from the ready list, if there.
1480
1481 // Add this thread to the clock timeout list.
1482 clock_list.link (timeout_node);
1483 timeout_node.thread.clock_node_ = &timeout_node;
1484
1485 state_ = state::suspended;
1486 // ----- Exit critical section ----------------------------------
1487 }
1488
1490
1491 {
1492 // ----- Enter critical section ---------------------------------
1493 interrupts::critical_section ics;
1494
1495 // Remove the thread from the clock timeout list,
1496 // if not already removed by the timer.
1497 timeout_node.thread.clock_node_ = nullptr;
1498 timeout_node.unlink ();
1499 // ----- Exit critical section ----------------------------------
1500 }
1501
1502 if (interrupted ())
1503 {
1504#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1505 trace::printf ("%s(0x%X,%u,%u) EINTR @%p %s\n", __func__, mask,
1506 timeout, mode, this, name ());
1507#endif
1508 return EINTR;
1509 }
1510
1511 if (clock_->steady_now () >= timeout_timestamp)
1512 {
1513#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1514 trace::printf ("%s(0x%X,%u,%u) ETIMEDOUT @%p %s\n", __func__,
1515 mask, timeout, mode, this, name ());
1516#endif
1517 return ETIMEDOUT;
1518 }
1519 }
1520
1521 return ENOTRECOVERABLE;
1522 }
1523
1536 thread::internal_flags_get_ (flags::mask_t mask, flags::mode_t mode)
1537 {
1538#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1539 trace::printf ("%s(0x%X) @%p %s\n", __func__, mask, this, name ());
1540#endif
1541
1542 // Don't call this from interrupt handlers.
1544
1545 flags::mask_t ret = event_flags_.get (mask, mode);
1546
1547#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1548 trace::printf ("%s(0x%X)=0x%X @%p %s\n", __func__, mask,
1549 event_flags_.mask (), this, name ());
1550#endif
1551 // Return the selected bits.
1552 return ret;
1553 }
1554
1558 result_t
1559 thread::internal_flags_clear_ (flags::mask_t mask, flags::mask_t* oflags)
1560 {
1561#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1562 trace::printf ("%s(0x%X) @%p %s <0x%X\n", __func__, mask, this, name (),
1563 event_flags_.mask ());
1564#endif
1565
1566 // Don't call this from interrupt handlers.
1568
1569 result_t res = event_flags_.clear (mask, oflags);
1570
1571#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1572 trace::printf ("%s(0x%X) @%p %s >0x%X\n", __func__, mask, this, name (),
1573 event_flags_.mask ());
1574#endif
1575 return res;
1576 }
1577
1582 // ------------------------------------------------------------------------
1588 namespace this_thread
1589 {
1590
1595 rtos::thread*
1596 _thread (void)
1597 {
1598 rtos::thread* th;
1599
1600#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1601
1602 th = port::this_thread::thread ();
1603
1604#else
1605
1606 th = scheduler::current_thread_;
1607
1608#endif
1609 return th;
1610 }
1611
1619 rtos::thread&
1620 thread (void)
1621 {
1622 // Don't call this from interrupt handlers.
1624
1625 rtos::thread* th;
1626
1627 th = _thread ();
1628
1629 // Could not get the current thread.
1630 assert(th != nullptr);
1631 return (*th);
1632 }
1633
1640 void
1641 yield (void)
1642 {
1643 // Don't call this from interrupt handlers.
1645
1646 if (!scheduler::started ())
1647 {
1648#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1649 trace::printf ("%s() nop %s \n", __func__, _thread ()->name ());
1650#endif
1651 return;
1652 }
1653
1654#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1655 trace::printf ("%s() from %s\n", __func__, _thread ()->name ());
1656#endif
1657
1658#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1659
1661
1662#else
1663
1665
1666#endif
1667
1668#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1669 trace::printf ("%s() to %s\n", __func__, _thread ()->name ());
1670#endif
1671 }
1672
1673 } /* namespace this_thread */
1674
1675 // --------------------------------------------------------------------------
1676 } /* namespace rtos */
1677} /* namespace os */
1678
1679// ----------------------------------------------------------------------------
object_named_system()
Construct a named system object instance.
Definition os-decls.h:767
const char * name(void) const
Get object name.
Definition os-decls.h:759
Interrupts critical section RAII helper.
Definition os-sched.h:498
Standard allocator based on the RTOS system default memory manager.
Definition os-memory.h:540
static void create(void *context, void *func, void *args)
Scheduler critical section RAII helper.
Definition os-sched.h:170
Thread attributes.
Definition os-thread.h:798
void initialize(void)
Align the pointers and initialise to a known pattern.
os::rtos::port::stack::element_t element_t
Type of a stack element.
Definition os-thread.h:439
static std::size_t min_size(void)
Get the min stack size.
Definition os-thread.h:2196
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
Definition os-thread.h:447
void clear(void)
Clear the stack pointer and size.
Definition os-thread.h:2130
std::size_t available(void)
Compute how much available stack remains.
static const element_t magic
Definition os-thread.h:449
stack::element_t * top(void)
Get the top stack address.
Definition os-thread.h:2160
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition os-thread.h:2140
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:250
result_t flags_raise(flags::mask_t mask, flags::mask_t *oflags=nullptr)
Raise thread event flags.
result_t kill(void)
Force thread termination.
virtual ~thread()
Destruct the thread object instance.
void *(*)(func_args_t args) func_t
Type of thread function.
Definition os-thread.h:420
void resume(void)
Resume the thread.
static const attributes initializer
Default thread initialiser.
Definition os-thread.h:1007
thread::stack & stack(void)
Get the thread context stack.
Definition os-thread.h:2445
priority_t priority_inherited(void)
Get the inherited scheduling priority.
bool interrupted(void)
Check if interrupted.
Definition os-thread.h:2367
memory::allocator< stack::allocation_element_t > allocator_type
Default RTOS allocator.
Definition os-thread.h:1014
result_t detach(void)
Detach a thread.
result_t cancel(void)
Cancel thread execution.
bool interrupt(bool interrupt=true)
Set the interrupt flag, possibly interrupting the thread.
_func_args_t func_args_t
Type of thread function arguments.
Definition os-thread.h:412
static bool is_constructed(const thread &thread)
Check if the thread is constructed.
Standard thread.
thread() noexcept=default
void join(void)
Definition thread-cpp.h:81
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:60
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:76
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.
allocator_stateless_default_resource< T > allocator
Type of allocator used by the system objects. Must be stateless.
Definition os-types.h:54
uint8_t priority_t
Type of variables holding thread priorities.
Definition os-thread.h:271
uint32_t mode_t
Type of variables holding flags modes.
Definition os-decls.h:275
uint32_t mask_t
Type of variables holding flags masks.
Definition os-decls.h:265
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1108
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:181
bool started(void)
Check if the scheduler was started.
Definition os-sched.h:827
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:856
thread & thread(void)
Get the current running thread.
void yield(void)
Yield execution to the next ready thread.
utils::intrusive_list< mutex, utils::double_list_links, &mutex::owner_links_ > mutexes_list
Definition os-mutex.cpp:294
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:96
System namespace.
A namespace for functions applying to the current thread.
#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.
Thread priorities.
Definition os-thread.h:282
@ running
Has the CPU and runs.
Definition os-thread.h:385
@ destroyed
Terminated and resources (like stack) released.
Definition os-thread.h:397
@ initializing
Used to check reused threads.
Definition os-thread.h:401
@ terminated
No longer usable, but resources not yet released.
Definition os-thread.h:393
@ ready
Present in the READY list and competing for CPU.
Definition os-thread.h:381
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:389