12#if defined(OS_USE_OS_APP_CONFIG_H)
13#include <cmsis-plus/os-app-config.h>
24#pragma clang diagnostic ignored "-Wc++98-compat"
39 std::size_t thread::stack::min_size_bytes_ = port::stack::min_size_bytes;
41 std::size_t thread::stack::default_size_bytes_
42 = port::stack::default_size_bytes;
49 using mutexes_list = utils::intrusive_list<mutex, utils::double_list_links,
50 &mutex::owner_links_>;
162 void* pa = bottom_address_;
170#pragma GCC diagnostic push
171#if defined(__clang__)
172#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
178 for (; p < pend; ++p)
182#pragma GCC diagnostic pop
185 size_bytes_ = ((
static_cast<std::size_t
> (p - bottom_address_) - 1)
204#pragma GCC diagnostic push
205#if defined(__clang__)
206#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
209 std::size_t count = 0;
215#pragma GCC diagnostic pop
235#if defined(OS_TRACE_RTOS_THREAD)
240#if defined(__EXCEPTIONS)
245 catch (std::exception
const& e)
247 trace::printf (
"%s() @%p %s top exception \"%s\"\n", __func__,
260 thread->internal_exit_ (exit_ptr);
265#if defined(OS_TRACE_RTOS_THREAD)
266 trace::printf (
"%s() @%p %s\n", __func__,
this, this->name ());
276#if defined(OS_TRACE_RTOS_THREAD)
277 trace::printf (
"%s() @%p %s\n", __func__,
this, this->name ());
363 :
thread{ nullptr, function, args, attr, allocator }
416 : object_named_system{ name }
418#if defined(OS_TRACE_RTOS_THREAD)
419 trace::printf (
"%s() @%p %s\n", __func__,
this, this->name ());
433 allocator_ = &allocator;
438 internal_construct_ (function, args, attr,
nullptr, 0);
442 using allocator_type2
447 allocated_stack_size_elements_
454 allocated_stack_size_elements_
460#pragma GCC diagnostic push
461#if defined(__clang__)
462#elif defined(__GNUC__)
463#pragma GCC diagnostic ignored "-Wuseless-cast"
466 const_cast<allocator_type2&
> (allocator).allocate (
467 allocated_stack_size_elements_));
468#pragma GCC diagnostic pop
471 assert (allocated_stack_address_ !=
nullptr);
473 internal_construct_ (function, args, attr, allocated_stack_address_,
474 allocated_stack_size_elements_
484 thread::internal_construct_ (func_t function, func_args_t args,
485 const attributes& attr,
void* stack_address,
486 std::size_t stack_size_bytes)
492 assert (function !=
nullptr);
496 clock_ = attr.clock !=
nullptr ? attr.clock : &
sysclock;
498 if (stack_address !=
nullptr)
504 assert (attr.th_stack_address ==
nullptr);
513 attr.th_stack_size_bytes);
516#if defined(OS_TRACE_RTOS_THREAD)
518 attr.th_priority,
stack ().bottom_address_,
519 stack ().size_bytes_);
525 scheduler::critical_section scs;
528 prio_assigned_ = attr.th_priority;
533 parent_ = this_thread::_thread ();
536 parent_->children_.link (*
this);
540 scheduler::top_threads_list_.link (*
this);
545#if defined(OS_USE_RTOS_PORT_SCHEDULER)
547 port::thread::create (
this);
552#pragma GCC diagnostic push
553#if defined(__clang__)
554#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
558 &context_,
reinterpret_cast<void*
> (internal_invoke_with_exit_),
560#pragma GCC diagnostic pop
564 scheduler::current_thread_ =
this;
597#if defined(OS_TRACE_RTOS_THREAD)
613#if defined(OS_TRACE_RTOS_THREAD)
614 trace::printf (
"%s() @%p %s nop, cannot commit suicide\n", __func__,
632#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
637#if defined(OS_USE_RTOS_PORT_SCHEDULER)
644 port::thread::resume (
this);
651 assert (port::interrupts::is_priority_valid ());
658 if (ready_node_.next () ==
nullptr)
660 scheduler::ready_threads_list_.link (ready_node_);
686 return prio_assigned_;
691 return (prio_inherited_ >= prio_assigned_) ? prio_inherited_
708 return prio_inherited_;
736#if defined(OS_TRACE_RTOS_THREAD)
746 if (prio_assigned_ == prio)
752 prio_assigned_ = prio;
756#if defined(OS_USE_RTOS_PORT_SCHEDULER)
759 res = port::thread::priority (
this, prio);
770 ready_node_.unlink ();
771 scheduler::ready_threads_list_.link (ready_node_);
804#if defined(OS_TRACE_RTOS_THREAD)
817 if (prio == prio_inherited_)
823 prio_inherited_ = prio;
825 if (prio_inherited_ < prio_assigned_)
833#if defined(OS_USE_RTOS_PORT_SCHEDULER)
836 res = port::thread::priority (
this, prio);
847 ready_node_.unlink ();
848 scheduler::ready_threads_list_.link (ready_node_);
885#if defined(OS_TRACE_RTOS_THREAD)
892#if defined(OS_USE_RTOS_PORT_SCHEDULER)
894 result_t res = port::thread::detach (
this);
943#if defined(OS_TRACE_RTOS_THREAD)
953 assert (
this != this_thread::_thread ());
957 joiner_ = this_thread::_thread ();
958 this_thread::_thread ()->internal_suspend_ ();
961#if defined(OS_TRACE_RTOS_THREAD)
965 if (exit_ptr !=
nullptr)
967 *exit_ptr = func_result_;
997#if defined(OS_TRACE_RTOS_THREAD)
1022#if defined(OS_TRACE_RTOS_THREAD)
1026 bool tmp = interrupted_;
1042 thread::internal_suspend_ (
void)
1044#if defined(OS_TRACE_RTOS_THREAD)
1063 thread::internal_exit_ (
void* exit_ptr)
1065#if defined(OS_TRACE_RTOS_THREAD)
1074 scheduler::critical_section scs;
1078 interrupts::critical_section ics;
1080 ready_node_.unlink ();
1082 child_links_.unlink ();
1087 assert (children_.empty ());
1091 func_args_ =
nullptr;
1094 assert (mutexes_.empty ());
1095 assert (acquired_mutexes_ == 0);
1097 func_result_ = exit_ptr;
1103 interrupts::critical_section ics;
1107 scheduler::terminated_threads_list_.link (ready_node_);
1111#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1113 port::thread::destroy_this (
this);
1132 thread::internal_check_stack_ (
void)
1134 if (stack ().size () > 0)
1136 if (!stack ().check_bottom_magic () || !stack ().check_top_magic ())
1139 assert (stack ().check_bottom_magic ());
1140 assert (stack ().check_top_magic ());
1143#if defined(OS_TRACE_RTOS_THREAD)
1145 "%s() @%p %s stack: %u/%u bytes used\n", __func__,
this,
name (),
1146 stack ().size () - stack ().available (), stack ().size ());
1154#pragma GCC diagnostic push
1155#if defined(__clang__)
1156#elif defined(__GNUC__)
1157#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
1161 thread::internal_destroy_ (
void)
1163#if defined(OS_TRACE_RTOS_THREAD)
1167 internal_check_stack_ ();
1169 if (allocated_stack_address_ !=
nullptr)
1172 typename std::allocator_traits<allocator_type>::pointer pointer;
1174#pragma GCC diagnostic push
1175#if defined(__clang__)
1176#elif defined(__GNUC__)
1177#pragma GCC diagnostic ignored "-Wuseless-cast"
1178#pragma GCC diagnostic ignored "-Wcast-align"
1182 reinterpret_cast<pointer
> (allocated_stack_address_),
1183 allocated_stack_size_elements_);
1184#pragma GCC diagnostic pop
1186 allocated_stack_address_ =
nullptr;
1191 scheduler::critical_section scs;
1194 while (not mx_list.empty ())
1196 auto* mx = mx_list.unlink_head ();
1198 mx->internal_mark_owner_dead_ ();
1201 mx->internal_unlock_ (
this);
1208 if (joiner_ !=
nullptr)
1213#pragma GCC diagnostic pop
1233#if defined(OS_TRACE_RTOS_THREAD)
1246#if defined(OS_TRACE_RTOS_THREAD)
1247 trace::printf (
"%s() @%p %s already gone\n", __func__,
this,
1258 ready_node_.unlink ();
1261 if (waiting_node_ !=
nullptr)
1263 waiting_node_->unlink ();
1267 if (clock_node_ !=
nullptr)
1269 clock_node_->unlink ();
1272 child_links_.unlink ();
1277 assert (children_.empty ());
1280#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1282 port::thread::destroy_other (
this);
1286 func_result_ =
nullptr;
1289 func_args_ =
nullptr;
1291 internal_destroy_ ();
1295 assert (mutexes_.empty ());
1296 assert (acquired_mutexes_ == 0);
1315#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1317 event_flags_.mask ());
1320 result_t res = event_flags_.raise (mask, oflags);
1324#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1326 event_flags_.mask ());
1340#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1341 trace::printf (
"%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode,
this,
1342 name (), event_flags_.mask ());
1354 if (event_flags_.check_raised (mask, oflags, mode))
1356#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1357 trace::printf (
"%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1358 this,
name (), event_flags_.mask ());
1365#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1372 interrupts::critical_section ics;
1374 if (event_flags_.check_raised (mask, oflags, mode))
1376#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1380 trace::printf (
"%s(0x%X,%u) in %d @%p %s >0x%X\n", __func__,
1381 mask, mode, slept_ticks,
this,
name (),
1382 event_flags_.mask ());
1389 internal_suspend_ ();
1393#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1394 trace::printf (
"%s(0x%X,%u) EINTR @%p %s\n", __func__, mask,
1395 mode,
this,
name ());
1402 return ENOTRECOVERABLE;
1410#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1411 trace::printf (
"%s(0x%X,%u) @%p %s <0x%X\n", __func__, mask, mode,
this,
1412 name (), event_flags_.mask ());
1420 interrupts::critical_section ics;
1422 if (event_flags_.check_raised (mask, oflags, mode))
1424#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1425 trace::printf (
"%s(0x%X,%u) @%p %s >0x%X\n", __func__, mask, mode,
1426 this,
name (), event_flags_.mask ());
1432#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1433 trace::printf (
"%s(0x%X,%u) EWOULDBLOCK @%p %s \n", __func__, mask,
1434 mode,
this,
name ());
1448#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1449 trace::printf (
"%s(0x%X,%u,%u) @%p %s <0x%X\n", __func__, mask, timeout,
1450 mode,
this,
name (), event_flags_.mask ());
1460 interrupts::critical_section ics;
1462 if (event_flags_.check_raised (mask, oflags, mode))
1464#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1465 trace::printf (
"%s(0x%X,%u,%u) @%p %s >0x%X\n", __func__, mask,
1466 timeout, mode,
this,
name (), event_flags_.mask ());
1473 internal::clock_timestamps_list& clock_list = clock_->steady_list ();
1476#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1481 internal::timeout_thread_node timeout_node{ timeout_timestamp, *
this };
1487 interrupts::critical_section ics;
1489 if (event_flags_.check_raised (mask, oflags, mode))
1491#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1495#pragma GCC diagnostic push
1496#if defined(__clang__)
1497#elif defined(__GNUC__)
1498#pragma GCC diagnostic ignored "-Wuseless-cast"
1500 trace::printf (
"%s(0x%X,%u,%u) in %u @%p %s >0x%X\n", __func__,
1501 mask, timeout, mode,
1502 static_cast<unsigned int> (slept_ticks),
this,
1503 name (), event_flags_.mask ());
1504#pragma GCC diagnostic pop
1513 clock_list.link (timeout_node);
1514 timeout_node.thread.clock_node_ = &timeout_node;
1524 interrupts::critical_section ics;
1528 timeout_node.thread.clock_node_ =
nullptr;
1529 timeout_node.unlink ();
1535#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1536 trace::printf (
"%s(0x%X,%u,%u) EINTR @%p %s\n", __func__, mask,
1537 timeout, mode,
this,
name ());
1542 if (clock_->steady_now () >= timeout_timestamp)
1544#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1545 trace::printf (
"%s(0x%X,%u,%u) ETIMEDOUT @%p %s\n", __func__,
1546 mask, timeout, mode,
this,
name ());
1552 return ENOTRECOVERABLE;
1569#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1578#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1580 event_flags_.mask (),
this,
name ());
1592#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1594 event_flags_.mask ());
1600 result_t res = event_flags_.clear (mask, oflags);
1602#if defined(OS_TRACE_RTOS_THREAD_FLAGS)
1604 event_flags_.mask ());
1631#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1633 th = port::this_thread::thread ();
1637 th = scheduler::current_thread_;
1661 assert (th !=
nullptr);
1679#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1680 trace::printf (
"%s() nop %s \n", __func__, _thread ()->name ());
1685#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1686 trace::printf (
"%s() from %s\n", __func__, _thread ()->name ());
1689#if defined(OS_USE_RTOS_PORT_SCHEDULER)
1699#if defined(OS_TRACE_RTOS_THREAD_CONTEXT)
1700 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.
std::size_t th_stack_size_bytes
Size of the user defined storage for the thread stack, in bytes.
bool th_enable_assert_reuse
void * th_stack_address
Address of the user defined storage for the thread stack.
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 default_size(void)
Get the default stack size.
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 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.
void *(*)(func_args_t args) func_t
Type of thread function.
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.
uint8_t priority_t
Type of variables holding thread priorities.
@ all
Special mask to represent all flags.
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.
@ undefined
Used to catch uninitialised threads.
@ suspended
Not present in the READY list, waiting for an event.