pw_thread/backends: Expand docs
Expands the docs for the pw_thread backends. Most notably the
ThreadX pw_thread docs are grossly expanded.
Also makes some small parallel changes to the ThreadX context and
option headers.
Change-Id: I53d35b83de8b914c566170d20f2509763ce6b4b1
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/70532
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Ewout van Bekkum <ewout@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
diff --git a/pw_thread_embos/docs.rst b/pw_thread_embos/docs.rst
index 7dd9f64..3bdbc4b 100644
--- a/pw_thread_embos/docs.rst
+++ b/pw_thread_embos/docs.rst
@@ -39,11 +39,11 @@
void StartExampleThread() {
pw::thread::DetachedThread(
pw::thread::embos::Options()
- .set_name("static_example_thread")
+ .set_name("example_thread")
.set_priority(kFooPriority)
.set_time_slice_interval(kFooTimeSliceInterval)
.set_context(example_thread_context),
- example_thread_function)
+ example_thread_function);
}
@@ -172,8 +172,7 @@
An ``Aborted`` error status is returned if the provided callback returns
``false`` to request an early termination of thread iteration.
-Return values
--------------
+*Return values*
* ``FailedPrecondition``: Returned when ``ForEachThread()`` is run before the OS
has been initialized.
@@ -186,8 +185,8 @@
This ``pw_thread`` backend provides helper functions that capture embOS thread
info to a ``pw::thread::Thread`` proto.
-SnapshotThread()/SnapshotThreads()
-==================================
+``SnapshotThreads()``
+=====================
``SnapshotThread()`` captures the thread name, state, and stack information for
the provided embOS TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
the most up-to-date information is captured, the stack pointer for the currently
diff --git a/pw_thread_freertos/docs.rst b/pw_thread_freertos/docs.rst
index d0f22c2..4e50030 100644
--- a/pw_thread_freertos/docs.rst
+++ b/pw_thread_freertos/docs.rst
@@ -41,7 +41,7 @@
.set_name("static_example_thread")
.set_priority(kFooPriority)
.set_static_context(example_thread_context),
- example_thread_function)
+ example_thread_function);
}
Alternatively when ``PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED`` is
@@ -182,8 +182,10 @@
from a thread.
---------
-utilities
+Utilities
---------
+``ForEachThread()``
+===================
In cases where an operation must be performed for every thread,
``ForEachThread()`` can be used to iterate over all the created thread TCBs.
Note that it's only safe to use this while the scheduler and interrupts are
@@ -195,8 +197,7 @@
An ``Aborted`` error status is returned if the provided callback returns
``false`` to request an early termination of thread iteration.
-Return values
-=============
+*Return values*
* ``FailedPrecondition``: Returned when ``ForEachThread()`` is run before the OS
has been initialized.
@@ -228,8 +229,8 @@
that this definition matches the size of FreeRTOS's ``StaticTask_T`` which is
the public opaque TCB type.
-SnapshotThread()/SnapshotThreads()
-==================================
+``SnapshotThreads()``
+=====================
``SnapshotThread()`` captures the thread name, state, and stack information for
the provided TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
the most up-to-date information is captured, the stack pointer for the currently
diff --git a/pw_thread_threadx/docs.rst b/pw_thread_threadx/docs.rst
index 116d1f1..4b73a40 100644
--- a/pw_thread_threadx/docs.rst
+++ b/pw_thread_threadx/docs.rst
@@ -8,6 +8,44 @@
.. 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<kFooStackSizeWords>
+ 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
@@ -78,9 +116,98 @@
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<ULONG>``
+ stack or the templated form of ``ContextWihtStack<kStackSizeWords`` can be
+ used.
+
+-----------------------------
+Thread Identification Backend
+-----------------------------
+A backend for ``pw::thread::Id`` and ``pw::thread::get_id()`` is offerred using
+``tx_thread_identify()``. It uses ``DASSERT`` to ensure that a thread is
+executing via ``TX_THREAD_GET_SYSTEM_STATE()``.
+
+--------------------
+Thread Sleep Backend
+--------------------
+A backend for ``pw::thread::sleep_for()`` and ``pw::thread::sleep_until()`` is
+offerred using ``tx_thread_sleep()`` if the duration is at least one tick, else
+``tx_thread_relinquish()`` is used. It uses
+``pw::this_thread::get_id() != thread::Id()`` to ensure it invoked only from a
+thread.
+
+--------------------
+Thread Yield Backend
+--------------------
+A backend for ``pw::thread::yield()`` is offered using via
+``tx_thread_relinquish()``. It uses
+``pw::this_thread::get_id() != thread::Id()`` to ensure it invoked only from a
+thread.
+
---------
-utilities
+Utilities
---------
+``ForEachThread()``
+===================
In cases where an operation must be performed for every thread,
``ForEachThread()`` can be used to iterate over all the created thread TCBs.
Note that it's only safe to use this while the scheduler is disabled.
@@ -88,8 +215,7 @@
An ``Aborted`` error status is returned if the provided callback returns
``false`` to request an early termination of thread iteration.
-Return values
-=============
+*Return values*
* ``Aborted``: The callback requested an early-termination of thread iteration.
* ``OkStatus``: The callback has been successfully run with every thread.
@@ -100,8 +226,8 @@
This ``pw_thread`` backend provides helper functions that capture ThreadX thread
state to a ``pw::thread::Thread`` proto.
-SnapshotThread()/SnapshotThreads()
-==================================
+``SnapshotThreads()``
+=====================
``SnapshotThread()`` captures the thread name, state, and stack information for
the provided ThreadX TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
the most up-to-date information is captured, the stack pointer for the currently
diff --git a/pw_thread_threadx/public/pw_thread_threadx/context.h b/pw_thread_threadx/public/pw_thread_threadx/context.h
index b36c420..8d5c87c 100644
--- a/pw_thread_threadx/public/pw_thread_threadx/context.h
+++ b/pw_thread_threadx/public/pw_thread_threadx/context.h
@@ -38,12 +38,12 @@
// std::array<ULONG, kFooStackSizeWords> example_thread_stack;
// pw::thread::threadx::Context example_thread_context(example_thread_stack);
// void StartExampleThread() {
-// pw::thread::Thread(
+// pw::thread::DetachedThread(
// pw::thread::threadx::Options()
-// .set_name("static_example_thread")
+// .set_name("example_thread")
// .set_priority(kFooPriority)
-// .set_static_context(example_thread_context),
-// example_thread_function).detach();
+// .set_context(example_thread_context),
+// example_thread_function);
// }
class Context {
public:
diff --git a/pw_thread_threadx/public/pw_thread_threadx/options.h b/pw_thread_threadx/public/pw_thread_threadx/options.h
index 7c130a1..079b587 100644
--- a/pw_thread_threadx/public/pw_thread_threadx/options.h
+++ b/pw_thread_threadx/public/pw_thread_threadx/options.h
@@ -31,7 +31,7 @@
// pw::thread::Thread example_thread(
// pw::thread::threadx::Options()
// .set_name("example_thread"),
-// .set_context(static_example_thread_context),
+// .set_context(example_thread_context),
// example_thread_function);
//
// // Specifies the name, priority, time slice interval, and pre-allocated
@@ -41,7 +41,7 @@
// .set_name("static_example_thread")
// .set_priority(kFooPriority)
// .set_time_slice_interval(1)
-// .set_context(static_example_thread_context),
+// .set_context(example_thread_context),
// example_thread_function);
//
class Options : public thread::Options {
@@ -61,6 +61,8 @@
// 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
constexpr Options& set_priority(UINT priority) {
PW_DASSERT(priority <= PW_THREAD_THREADX_CONFIG_MIN_PRIORITY);
priority_ = priority;
@@ -108,8 +110,10 @@
return *this;
}
- // Set the pre-allocated context (all memory needed to run a thread), see the
- // pw::thread::threadx::Context for more detail.
+ // 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<ULONG> stack
+ // or the templated form of ContextWihtStack<kStackSizeWords> can be used.
constexpr Options& set_context(Context& context) {
context_ = &context;
return *this;