blob: 3bdbc4b0733306247e29129c5b9452d93bdff84a [file] [log] [blame]
Ewout van Bekkum8b72a572021-03-09 08:53:39 -08001.. _module-pw_thread_embos:
2
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -07003===============
Ewout van Bekkum8b72a572021-03-09 08:53:39 -08004pw_thread_embos
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -07005===============
6This is a set of backends for pw_thread based on embOS v4.
Ewout van Bekkum8b72a572021-03-09 08:53:39 -08007
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -07008.. Warning::
9 This module is still under construction, the API is not yet stable.
10
11-----------------------
12Thread Creation Backend
13-----------------------
14A backend or ``pw::thread::Thread`` is offered using ``OS_CreateTaskEx()``.
15Optional joining support is enabled via an ``OS_EVENT`` in each thread's
16context.
17
18This backend permits users to start threads where contexts must be explicitly
19allocated and passed in as an option. As a quick example, a detached thread
20can be created as follows:
21
22.. code-block:: cpp
23
24 #include "pw_thread/detached_thread.h"
Ewout van Bekkumc2931da2021-07-27 16:39:48 -070025 #include "pw_thread_embos/config.h"
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -070026 #include "pw_thread_embos/context.h"
27 #include "pw_thread_embos/options.h"
28 #include "RTOS.h" // For the embOS types.
29
Ewout van Bekkumc2931da2021-07-27 16:39:48 -070030 constexpr OS_PRIO kFooPriority =
31 pw::thread::embos::config::kDefaultPriority;
32 constexpr OS_UINT kFooTimeSliceInterval =
33 pw::thread::embos::config::kDefaultTimeSliceInterval;
34 constexpr size_t kFooStackSizeWords =
35 pw::thread::embos::config::kDefaultStackSizeWords;
36
37 pw::thread::embos::ContextWithStack<kFooStackSizeWords>
38 example_thread_context;
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -070039 void StartExampleThread() {
40 pw::thread::DetachedThread(
41 pw::thread::embos::Options()
Ewout van Bekkumd5a42202021-11-23 14:59:39 -080042 .set_name("example_thread")
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -070043 .set_priority(kFooPriority)
44 .set_time_slice_interval(kFooTimeSliceInterval)
45 .set_context(example_thread_context),
Ewout van Bekkumd5a42202021-11-23 14:59:39 -080046 example_thread_function);
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -070047 }
48
49
50Module Configuration Options
51============================
52The following configurations can be adjusted via compile-time configuration of
53this module, see the
54:ref:`module documentation <module-structure-compile-time-configuration>` for
55more details.
56
57.. c:macro:: PW_THREAD_EMBOS_CONFIG_JOINING_ENABLED
58
59 Whether thread joining is enabled. By default this is disabled.
60
61 We suggest only enabling this when thread joining is required to minimize
62 the RAM and ROM cost of threads.
63
64 Enabling this grows the RAM footprint of every pw::thread::Thread as it adds
65 an OS_EVENT to every thread's pw::thread::embos::Context. In addition, there
66 is a minute ROM cost to construct and destroy this added object.
67
68 PW_THREAD_JOINING_ENABLED gets set to this value.
69
70.. c:macro:: PW_THREAD_EMBOS_CONFIG_MINIMUM_STACK_SIZE_WORDS
71
72 The minimum stack size in words. By default this uses Segger's recommendation
73 of 68 bytes.
74
75.. c:macro:: PW_THREAD_EMBOS_CONFIG_DEFAULT_STACK_SIZE_WORDS
76
77 The default stack size in words. By default this uses Segger's recommendation
78 of 256 bytes to start.
79
80.. c:macro:: PW_THREAD_EMBOS_CONFIG_MAX_THREAD_NAME_LEN
81
82 The maximum length of a thread's name, not including null termination. By
83 default this is arbitrarily set to 15. This results in an array of characters
84 which is this length + 1 bytes in every ``pw::thread::Thread``'s context.
85
86.. c:macro:: PW_THREAD_EMBOS_CONFIG_MIN_PRIORITY
87
88 The minimum priority level, this is normally 1, since 0 is not a valid
89 priority level.
90
91.. c:macro:: PW_THREAD_EMBOS_CONFIG_DEFAULT_PRIORITY
92
93 The default priority level. By default this uses the minimal embOS priority.
94
95.. c:macro:: PW_THREAD_EMBOS_CONFIG_DEFAULT_TIME_SLICE_INTERVAL
96
97 The round robin time slice tick interval for threads at the same priority.
98 By default this is set to 2 ticks based on the embOS default.
99
Armando Montanez5f10ff82021-08-13 13:47:39 -0700100.. c:macro:: PW_THREAD_EMBOS_CONFIG_LOG_LEVEL
101
102 The log level to use for this module. Logs below this level are omitted.
Ewout van Bekkum6e5d43e2021-05-06 15:29:44 -0700103
104embOS Thread Options
105====================
106.. cpp:class:: pw::thread::embos::Options
107
108 .. cpp:function:: set_name(const char* name)
109
110 Sets the name for the embOS task, this is optional.
111 Note that this will be deep copied into the context and may be truncated
112 based on ``PW_THREAD_EMBOS_CONFIG_MAX_THREAD_NAME_LEN``.
113
114 .. cpp:function:: set_priority(OS_PRIO priority)
115
116 Sets the priority for the embOS task. Higher values are higher priority,
117 see embOS OS_CreateTaskEx for more detail.
118 Precondition: This must be >= ``PW_THREAD_EMBOS_CONFIG_MIN_PRIORITY``.
119
120 .. cpp:function:: set_time_slice_interval(OS_UINT time_slice_interval)
121
122 Sets the number of ticks this thread is allowed to run before other ready
123 threads of the same priority are given a chance to run.
124
125 A value of 0 disables time-slicing of this thread.
126
127 Precondition: This must be <= 255 ticks.
128
129 .. cpp:function:: set_context(pw::thread::embos::Context& context)
130
131 Set the pre-allocated context (all memory needed to run a thread). Note that
132 this is required for this thread creation backend! The ``Context`` can
133 either be constructed with an externally provided ``std::span<OS_UINT>``
134 stack or the templated form of ``ContextWithStack<kStackSizeWords>`` can
135 be used.
136
137
138-----------------------------
139Thread Identification Backend
140-----------------------------
141A backend for ``pw::thread::Id`` and ``pw::thread::get_id()`` is offerred using
142``OS_GetTaskID()``. It uses ``DASSERT`` to ensure that the scheduler has started
143via ``OS_IsRunning()``.
144
145--------------------
146Thread Sleep Backend
147--------------------
148A backend for ``pw::thread::sleep_for()`` and ``pw::thread::sleep_until()`` is
149offerred using ``OS_Delay()`` if the duration is at least one tick, else
150``OS_Yield()`` is used. It uses ``pw::this_thread::get_id() != thread::Id()`` to
151ensure it invoked only from a thread.
152
153--------------------
154Thread Yield Backend
155--------------------
156A backend for ``pw::thread::yield()`` is offered using via ``OS_Yield()``.
157It uses ``pw::this_thread::get_id() != thread::Id()`` to ensure it invoked only
158from a thread.
Armando Montanez952f2d52021-06-30 16:27:47 -0700159
160---------
161Utilities
162---------
163``ForEachThread()``
164===================
165In cases where an operation must be performed for every thread,
166``ForEachThread()`` can be used to iterate over all the created thread TCBs.
167Note that it's only safe to use this while the scheduler is suspended, and this
168should only be used after ``OS_Start()`` has been called. Calling this before
169the scheduler has started is non-fatal, but will result in no action and a
170``FailedPrecondition`` error code.
171
Armando Montanez5d4eed62021-07-19 10:15:09 -0700172An ``Aborted`` error status is returned if the provided callback returns
173``false`` to request an early termination of thread iteration.
174
Ewout van Bekkumd5a42202021-11-23 14:59:39 -0800175*Return values*
Armando Montanez952f2d52021-06-30 16:27:47 -0700176
177* ``FailedPrecondition``: Returned when ``ForEachThread()`` is run before the OS
178 has been initialized.
Armando Montanez5d4eed62021-07-19 10:15:09 -0700179* ``Aborted``: The callback requested an early-termination of thread iteration.
Armando Montanez952f2d52021-06-30 16:27:47 -0700180* ``OkStatus``: The callback has been successfully run with every thread.
Armando Montanez952f2d52021-06-30 16:27:47 -0700181
182--------------------
183Snapshot Integration
184--------------------
185This ``pw_thread`` backend provides helper functions that capture embOS thread
186info to a ``pw::thread::Thread`` proto.
187
Ewout van Bekkumd5a42202021-11-23 14:59:39 -0800188``SnapshotThreads()``
189=====================
Armando Montanez952f2d52021-06-30 16:27:47 -0700190``SnapshotThread()`` captures the thread name, state, and stack information for
191the provided embOS TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
192the most up-to-date information is captured, the stack pointer for the currently
193running thread must be provided for cases where the running thread is being
194captured. For ARM Cortex-M CPUs, you can do something like this:
195
196.. Code:: cpp
197
198 // Capture PSP.
199 void* stack_ptr = 0;
200 asm volatile("mrs %0, psp\n" : "=r"(stack_ptr));
201 pw::thread::ProcessThreadStackCallback cb =
202 [](pw::thread::Thread::StreamEncoder& encoder,
203 pw::ConstByteSpan stack) -> pw::Status {
204 return encoder.WriteRawStack(stack);
205 };
206 pw::thread::embos::SnapshotThread(my_thread, stack_ptr,
207 snapshot_encoder, cb);
208
209``SnapshotThreads()`` wraps the singular thread capture to instead captures
210all created threads to a ``pw::thread::SnapshotThreadInfo`` message. This proto
211message overlays a snapshot, so it is safe to static cast a
212``pw::snapshot::Snapshot::StreamEncoder`` to a
213``pw::thread::SnapshotThreadInfo::StreamEncoder`` when calling this function.
214
215Thread Name Capture
216-------------------
217In order to capture thread names when snapshotting a thread, embOS must have
218``OS_TRACKNAME`` enabled. If ``OS_TRACKNAME`` is disabled, no thread name
219is captured. Enabling this is strongly recommended for debugability.
220
221Thread State Capture
222--------------------
223embOS thread state is not part of embOS's public API. Despite this, the
224snapshot integration captures thread state based on information on how the
225thread state is represented from
226`Segger's public forum <https://forum.segger.com/index.php/Thread/6548-ABANDONED-Task-state-values/?postID=23963#post23963>`_.
227This has been tested on embOS 4.22, and was initially
228reported for embOS 5.06. The logic Pigweed uses to interpret thread state may
229be incorrect for other versions of embOS.
230
231Thread Stack Capture
232--------------------
233Full thread stack information capture is dependent on embOS tracking the stack
234bounds for each task. When either ``OS_SUPPORT_MPU`` or ``OS_CHECKSTACK`` are
235enabled, stack bounds are tracked and the callback for thread stack dumping
236will be called. If both of these options are disabled, ``stack_start_pointer``
237and ``stack_end_pointer`` will not be captured, and the
238``ProcessThreadStackCallback`` will not be called.