.. _module-pw_thread_threadx: ================= pw_thread_threadx ================= This is a set of backends for pw_thread based on ThreadX. .. Warning:: This module is still under construction, the API is not yet stable. ----------------------- Thread Creation Backend ----------------------- A backend for ``pw::thread::Thread`` is offered using ``tx_thread_create``. Optional joining support is enabled via an ``TX_EVENT_FLAGS_GROUP`` in each thread's context. This backend permits users to start threads where contexts must be explicitly allocated and passed in as an option. As a quick example, a detached thread can be created as follows: .. code-block:: cpp #include "pw_thread/detached_thread.h" #include "pw_thread_threadx/config.h" #include "pw_thread_threadx/context.h" #include "pw_thread_threadx/options.h" #include "tx_api.h" constexpr UINT kFooPriority = pw::thread::threadx::config::kDefaultPriority; constexpr ULONG kFooTimeSliceInterval = pw::thread::threadx::config::kDefaultTimeSliceInterval; constexpr size_t kFooStackSizeWords = pw::thread::threadx::config::kDefaultStackSizeWords; pw::thread::threadx::ContextWithStack example_thread_context; void StartExampleThread() { pw::thread::DetachedThread( pw::thread::threadx::Options() .set_name("example_thread") .set_priority(kFooPriority) .set_time_slice_interval(kFooTimeSliceInterval) .set_context(example_thread_context), example_thread_function); } .. list-table:: * - :ref:`module-pw_thread` Facade - Backend Target - Description * - ``pw_thread:id`` - ``pw_thread_threadx:id`` - Thread identification. * - ``pw_thread:yield`` - ``pw_thread_threadx:yield`` - Thread scheduler yielding. * - ``pw_thread:sleep`` - ``pw_thread_threadx:sleep`` - Thread scheduler sleeping. * - ``pw_thread:thread`` - ``pw_thread_threadx:thread`` - Thread creation. Module Configuration Options ============================ The following configurations can be adjusted via compile-time configuration of this module, see the :ref:`module documentation ` for more details. .. c:macro:: PW_THREAD_THREADX_CONFIG_JOINING_ENABLED Whether thread joining is enabled. By default this is disabled. We suggest only enabling this when thread joining is required to minimize the RAM and ROM cost of threads. Enabling this grows the RAM footprint of every pw::thread::Thread as it adds a TX_EVENT_FLAGS_GROUP to every thread's pw::thread::threadx::Context. In addition, there is a minute ROM cost to construct and destroy this added object. PW_THREAD_JOINING_ENABLED gets set to this value. .. c:macro:: PW_THREAD_THREADX_CONFIG_DEFAULT_STACK_SIZE_WORDS The default stack size in words. By default this uses the minimal ThreadX stack size. .. c:macro:: PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN The maximum length of a thread's name, not including null termination. By default this is arbitrarily set to 15. This results in an array of characters which is this length + 1 bytes in every pw::thread::Thread's context. .. c:macro:: PW_THREAD_THREADX_CONFIG_DEFAULT_TIME_SLICE_INTERVAL The round robin time slice tick interval for threads at the same priority. By default this is disabled as not all ports support this, using a value of 0 ticks. .. c:macro:: PW_THREAD_THREADX_CONFIG_MIN_PRIORITY The minimum priority level, this is normally based on the number of priority levels. .. c:macro:: PW_THREAD_THREADX_CONFIG_DEFAULT_PRIORITY The default priority level. By default this uses the minimal ThreadX priority level, given that 0 is the highest priority. .. c:macro:: PW_THREAD_THREADX_CONFIG_LOG_LEVEL The log level to use for this module. Logs below this level are omitted. ThreadX Thread Options ====================== .. cpp:class:: pw::thread::threadx::Options .. cpp:function:: set_name(const char* name) Sets the name for the ThreadX thread, note that this will be deep copied into the context and may be truncated based on ``PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN``. .. cpp:function:: set_priority(UINT priority) Sets the priority for the ThreadX thread from 0 through 31, where a value of 0 represents the highest priority, see ThreadX tx_thread_create for more detail. **Precondition**: priority <= ``PW_THREAD_THREADX_CONFIG_MIN_PRIORITY``. .. cpp:function:: set_preemption_threshold(UINT preemption_threshold) Optionally sets the preemption threshold for the ThreadX thread from 0 through 31. Only priorities higher than this level (i.e. lower number) are allowed to preempt this thread. In other words this allows the thread to specify the priority ceiling for disabling preemption. Threads that have a higher priority than the ceiling are still allowed to preempt while those with less than the ceiling are not allowed to preempt. Not setting the preemption threshold or explicitly specifying a value equal to the priority disables preemption threshold. Time slicing is disabled while the preemption threshold is enabled, i.e. not equal to the priority, even if a time slice interval was specified. The preemption threshold can be adjusted at run time, this only sets the initial threshold. **Precondition**: preemption_threshold <= priority .. cpp:function:: set_time_slice_interval(UINT time_slice_interval) Sets the number of ticks this thread is allowed to run before other ready threads of the same priority are given a chance to run. Time slicing is disabled while the preemption threshold is enabled, i.e. not equal to the priority, even if a time slice interval was specified. A value of ``TX_NO_TIME_SLICE`` (a value of 0) disables time-slicing of this thread. Using time slicing results in a slight amount of system overhead, threads with a unique priority should consider ``TX_NO_TIME_SLICE``. .. cpp:function:: set_context(pw::thread::embos::Context& context) Set the pre-allocated context (all memory needed to run a thread). Note that this is required for this thread creation backend! The Context can either be constructed with an externally provided ``std::span`` stack or the templated form of ``ContextWihtStack pw::Status { return encoder.WriteRawStack(stack); }; pw::thread::threadx::SnapshotThread(my_thread, stack_ptr, snapshot_encoder, cb); ``SnapshotThreads()`` wraps the singular thread capture to instead captures all created threads to a ``pw::thread::SnapshotThreadInfo`` message. This proto message overlays a snapshot, so it is safe to static cast a ``pw::snapshot::Snapshot::StreamEncoder`` to a ``pw::thread::SnapshotThreadInfo::StreamEncoder`` when calling this function.