13#if defined(OS_USE_OS_APP_CONFIG_H)
14#include <cmsis-plus/os-app-config.h>
25#pragma clang diagnostic ignored "-Wc++98-compat"
40 std::size_t thread::stack::min_size_bytes_ = port::stack::min_size_bytes;
42 std::size_t thread::stack::default_size_bytes_ =
43 port::stack::default_size_bytes;
51 mutex, utils::double_list_links, &mutex::owner_links_>;
156 void* pa = bottom_address_;
168 for (; p < pend; ++p)
174 size_bytes_ = ((
static_cast<std::size_t
> (p - bottom_address_) - 1)
194 std::size_t count = 0;
219#if defined(OS_TRACE_RTOS_THREAD)
224#if defined(__EXCEPTIONS)
229 catch (std::exception
const &e)
231 trace::printf (
"%s() @%p %s top exception \"%s\"\n", __func__,
244 thread->internal_exit_ (exit_ptr);
249#if defined(OS_TRACE_RTOS_THREAD)
262#if defined(OS_TRACE_RTOS_THREAD)
348 {
nullptr, function, args, attr, allocator }
401#if defined(OS_TRACE_RTOS_THREAD)
402 trace::printf (
"%s() @%p %s\n", __func__,
this, this->name ());
406 if (attr.th_enable_assert_reuse) {
408 assert((state_ == state::undefined) || (state_ == state::destroyed));
412 state_ = state::initializing;
414 allocator_ = &allocator;
416 if (attr.th_stack_address !=
nullptr
417 && attr.th_stack_size_bytes > stack::min_size ())
419 internal_construct_ (function, args, attr,
nullptr, 0);
423 using allocator_type2 = memory::allocator<stack::allocation_element_t>;
425 if (attr.th_stack_size_bytes > stack::min_size ())
427 allocated_stack_size_elements_ = (attr.th_stack_size_bytes
428 +
sizeof(stack::allocation_element_t) - 1)
429 /
sizeof(stack::allocation_element_t);
433 allocated_stack_size_elements_ = (stack::default_size ()
434 +
sizeof(stack::allocation_element_t) - 1)
435 /
sizeof(stack::allocation_element_t);
438#pragma GCC diagnostic push
439#if defined(__clang__)
440#elif defined(__GNUC__)
441#pragma GCC diagnostic ignored "-Wuseless-cast"
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
449 assert(allocated_stack_address_ !=
nullptr);
451 internal_construct_ (
455 allocated_stack_address_,
456 allocated_stack_size_elements_
457 *
sizeof(stack::allocation_element_t));
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)
474 assert(function !=
nullptr);
478 clock_ = attr.clock !=
nullptr ? attr.clock : &
sysclock;
480 if (stack_address !=
nullptr)
486 assert(attr.th_stack_address ==
nullptr);
495 attr.th_stack_size_bytes);
498#if defined(OS_TRACE_RTOS_THREAD)
500 attr.th_priority,
stack ().bottom_address_,
501 stack ().size_bytes_);
507 scheduler::critical_section scs;
510 prio_assigned_ = attr.th_priority;
515 parent_ = this_thread::_thread ();
518 parent_->children_.link (*
this);
522 scheduler::top_threads_list_.link (*
this);
527#if defined(OS_USE_RTOS_PORT_SCHEDULER)
529 port::thread::create (
this);
534#pragma GCC diagnostic push
535#if defined(__clang__)
536#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
540 &context_,
reinterpret_cast<void*
> (internal_invoke_with_exit_),
542#pragma GCC diagnostic pop
546 scheduler::current_thread_ =
this;
579#if defined(OS_TRACE_RTOS_THREAD)
595#if defined(OS_TRACE_RTOS_THREAD)
596 trace::printf (
"%s() @%p %s nop, cannot commit suicide\n", __func__,
614#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
619#if defined(OS_USE_RTOS_PORT_SCHEDULER)
626 port::thread::resume (
this);
633 assert(port::interrupts::is_priority_valid ());
640 if (ready_node_.next () ==
nullptr)
642 scheduler::ready_threads_list_.link (ready_node_);
669 return prio_assigned_;
675 (prio_inherited_ >= prio_assigned_) ?
676 prio_inherited_ : prio_assigned_;
692 return prio_inherited_;
717#if defined(OS_TRACE_RTOS_THREAD)
727 if (prio_assigned_ == prio)
733 prio_assigned_ = prio;
737#if defined(OS_USE_RTOS_PORT_SCHEDULER)
740 res = port::thread::priority (
this, prio);
751 ready_node_.unlink ();
752 scheduler::ready_threads_list_.link (ready_node_);
785#if defined(OS_TRACE_RTOS_THREAD)
798 if (prio == prio_inherited_)
804 prio_inherited_ = prio;
806 if (prio_inherited_ < prio_assigned_)
814#if defined(OS_USE_RTOS_PORT_SCHEDULER)
817 res = port::thread::priority (
this, prio);
828 ready_node_.unlink ();
829 scheduler::ready_threads_list_.link (ready_node_);
863#if defined(OS_TRACE_RTOS_THREAD)
870#if defined(OS_USE_RTOS_PORT_SCHEDULER)
872 result_t res = port::thread::detach (
this);
918#if defined(OS_TRACE_RTOS_THREAD)
928 assert(
this != this_thread::_thread ());
932 joiner_ = this_thread::_thread ();
933 this_thread::_thread ()->internal_suspend_ ();
936#if defined(OS_TRACE_RTOS_THREAD)
940 if (exit_ptr !=
nullptr)
942 *exit_ptr = func_result_;
969#if defined(OS_TRACE_RTOS_THREAD)
994#if defined(OS_TRACE_RTOS_THREAD)
998 bool tmp = interrupted_;
1014 thread::internal_suspend_ (
void)
1016#if defined(OS_TRACE_RTOS_THREAD)
1035 thread::internal_exit_ (
void* exit_ptr)
1037#if defined(OS_TRACE_RTOS_THREAD)
1046 scheduler::critical_section scs;
1050 interrupts::critical_section ics;
1052 ready_node_.unlink ();
1054 child_links_.unlink ();
1059 assert(children_.empty ());
1063 func_args_ =
nullptr;
1066 assert(mutexes_.empty ());
1067 assert(acquired_mutexes_ == 0);
1069 func_result_ = exit_ptr;
1075 interrupts::critical_section ics;
1079 scheduler::terminated_threads_list_.link (ready_node_);
1083#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1085 port::thread::destroy_this (
this);
1104 thread::internal_check_stack_ (
void)
1106 if (stack ().size () > 0)
1108 if (!stack ().check_bottom_magic () || !stack ().check_top_magic ())
1111 assert(stack ().check_bottom_magic ());
1112 assert(stack ().check_top_magic ());
1115#if defined(OS_TRACE_RTOS_THREAD)
1116 trace::printf (
"%s() @%p %s stack: %u/%u bytes used\n", __func__,
1118 stack ().size () - stack ().available (),
1127#pragma GCC diagnostic push
1128#if defined(__clang__)
1129#elif defined(__GNUC__)
1130#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
1134 thread::internal_destroy_ (
void)
1136#if defined(OS_TRACE_RTOS_THREAD)
1140 internal_check_stack_ ();
1142 if (allocated_stack_address_ !=
nullptr)
1144 typedef typename std::allocator_traits<allocator_type>::pointer pointer;
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"
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
1157 allocated_stack_address_ =
nullptr;
1162 scheduler::critical_section scs;
1165 while (not mx_list.empty ())
1167 auto* mx = mx_list.unlink_head ();
1169 mx->internal_mark_owner_dead_ ();
1172 mx->internal_unlock_ (
this);
1179 if (joiner_ !=
nullptr)
1184#pragma GCC diagnostic pop
1201#if defined(OS_TRACE_RTOS_THREAD)
1214#if defined(OS_TRACE_RTOS_THREAD)
1215 trace::printf (
"%s() @%p %s already gone\n", __func__,
this,
1226 ready_node_.unlink ();
1229 if (waiting_node_ !=
nullptr)
1231 waiting_node_->unlink ();
1235 if (clock_node_ !=
nullptr)
1237 clock_node_->unlink ();
1240 child_links_.unlink ();
1245 assert(children_.empty ());
1248#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1250 port::thread::destroy_other (
this);
1254 func_result_ =
nullptr;
1257 func_args_ =
nullptr;
1259 internal_destroy_ ();
1263 assert(mutexes_.empty ());
1264 assert(acquired_mutexes_ == 0);
1283#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1285 event_flags_.mask ());
1288 result_t res = event_flags_.raise (mask, oflags);
1292#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1294 event_flags_.mask ());
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 ());
1322 if (event_flags_.check_raised (mask, oflags, mode))
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 ());
1333#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1340 interrupts::critical_section ics;
1342 if (event_flags_.check_raised (mask, oflags, mode))
1344#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
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 ());
1357 internal_suspend_ ();
1361#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1362 trace::printf (
"%s(0x%X,%u) EINTR @%p %s\n", __func__, mask, mode,
1370 return ENOTRECOVERABLE;
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 ());
1387 interrupts::critical_section ics;
1389 if (event_flags_.check_raised (mask, oflags, mode))
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 ());
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 ());
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 ());
1427 interrupts::critical_section ics;
1429 if (event_flags_.check_raised (mask, oflags, mode))
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 ());
1441 internal::clock_timestamps_list& clock_list = clock_->steady_list ();
1444#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1449 internal::timeout_thread_node timeout_node
1450 { timeout_timestamp, *
this };
1456 interrupts::critical_section ics;
1458 if (event_flags_.check_raised (mask, oflags, mode))
1460#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1464#pragma GCC diagnostic push
1465#if defined(__clang__)
1466#elif defined(__GNUC__)
1467#pragma GCC diagnostic ignored "-Wuseless-cast"
1470 __func__, mask, timeout, mode,
1471 static_cast<unsigned int> (slept_ticks),
this,
1472 name (), event_flags_.mask ());
1473#pragma GCC diagnostic pop
1482 clock_list.link (timeout_node);
1483 timeout_node.thread.clock_node_ = &timeout_node;
1493 interrupts::critical_section ics;
1497 timeout_node.thread.clock_node_ =
nullptr;
1498 timeout_node.unlink ();
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 ());
1511 if (clock_->steady_now () >= timeout_timestamp)
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 ());
1521 return ENOTRECOVERABLE;
1538#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1547#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1549 event_flags_.mask (),
this,
name ());
1561#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1563 event_flags_.mask ());
1569 result_t res = event_flags_.clear (mask, oflags);
1571#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1573 event_flags_.mask ());
1600#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1602 th = port::this_thread::thread ();
1606 th = scheduler::current_thread_;
1630 assert(th !=
nullptr);
1648#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1649 trace::printf (
"%s() nop %s \n", __func__, _thread ()->name ());
1654#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1655 trace::printf (
"%s() from %s\n", __func__, _thread ()->name ());
1658#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1668#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1669 trace::printf (
"%s() to %s\n", __func__, _thread ()->name ());
object_named_system()
Construct a named system object instance.
const char * name(void) const
Get object name.
Interrupts critical section RAII helper.
Standard allocator based on the RTOS system default memory manager.
static void create(void *context, void *func, void *args)
Scheduler critical section RAII helper.
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.
static std::size_t min_size(void)
Get the min stack size.
os::rtos::port::stack::allocation_element_t allocation_element_t
Type of a stack allocation element.
void clear(void)
Clear the stack pointer and size.
std::size_t available(void)
Compute how much available stack remains.
static const element_t magic
stack::element_t * top(void)
Get the top stack address.
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
POSIX compliant thread, using the default RTOS allocator.
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.
void resume(void)
Resume the thread.
static const attributes initializer
Default thread initialiser.
thread::stack & stack(void)
Get the thread context stack.
priority_t priority_inherited(void)
Get the inherited scheduling priority.
bool interrupted(void)
Check if interrupted.
memory::allocator< stack::allocation_element_t > allocator_type
Default RTOS allocator.
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.
static bool is_constructed(const thread &thread)
Check if the thread is constructed.
thread() noexcept=default
int printf(const char *format,...)
Write a formatted string to the trace device.
port::clock::duration_t duration_t
Type of variables holding clock durations.
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
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.
uint8_t priority_t
Type of variables holding thread priorities.
uint32_t mode_t
Type of variables holding flags modes.
uint32_t mask_t
Type of variables holding flags masks.
bool in_handler_mode(void)
Check if the CPU is in handler mode.
void prepare_suspend(void)
@ ok
Function completed; no errors or events occurred.
bool started(void)
Check if the scheduler was started.
bool locked(void)
Check if the scheduler is locked.
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
uint32_t result_t
Type of values returned by RTOS functions.
A namespace for functions applying to the current thread.
#define os_assert_throw(__e, __er)
Assert or throw a system error exception.
#define os_assert_err(__e, __er)
Assert or return an error.
Single file µOS++ RTOS definitions.
@ running
Has the CPU and runs.
@ destroyed
Terminated and resources (like stack) released.
@ initializing
Used to check reused threads.
@ terminated
No longer usable, but resources not yet released.
@ ready
Present in the READY list and competing for CPU.
@ suspended
Not present in the READY list, waiting for an event.