xref: /aosp_15_r20/external/pigweed/pw_thread_threadx/public/pw_thread_threadx/options.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <optional>
17 
18 #include "pw_assert/assert.h"
19 #include "pw_thread/thread.h"
20 #include "pw_thread_threadx/config.h"
21 #include "pw_thread_threadx/context.h"
22 #include "tx_api.h"
23 
24 namespace pw::thread::threadx {
25 
26 class Context;
27 
28 // pw::thread::Options for ThreadX.
29 //
30 // Example usage:
31 //
32 //   // Uses the default priority and time slice interval (which may be
33 //   // disabled), but specifies a custom name and pre-allocated context.
34 //   // Note that the preemption threshold is disabled by default.
35 //   pw::Thread example_thread(
36 //     pw::thread::threadx::Options()
37 //         .set_name("example_thread"),
38 //         .set_context(example_thread_context),
39 //     example_thread_function);
40 //
41 //   // Specifies the name, priority, time slice interval, and pre-allocated
42 //   // context, but does not use a preemption threshold.
43 //   pw::Thread static_example_thread(
44 //     pw::thread::threadx::Options()
45 //         .set_name("static_example_thread")
46 //         .set_priority(kFooPriority)
47 //         .set_time_slice_interval(1)
48 //         .set_context(example_thread_context),
49 //     example_thread_function);
50 //
51 class Options : public thread::Options {
52  public:
53   constexpr Options() = default;
54   constexpr Options(const Options&) = default;
55   constexpr Options(Options&&) = default;
56 
57   // Sets the name for the ThreadX thread, note that this will be deep copied
58   // into the context and may be truncated based on
59   // PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN.
set_name(const char * name)60   constexpr Options& set_name(const char* name) {
61     name_ = name;
62     return *this;
63   }
64 
65   // Sets the priority for the ThreadX thread from 0 through 31, where a value
66   // of 0 represents the highest priority, see ThreadX tx_thread_create for
67   // more detail.
68   //
69   // Precondition: priority <= PW_THREAD_THREADX_CONFIG_MIN_PRIORITY
set_priority(UINT priority)70   constexpr Options& set_priority(UINT priority) {
71     PW_DASSERT(priority <= PW_THREAD_THREADX_CONFIG_MIN_PRIORITY);
72     priority_ = priority;
73     return *this;
74   }
75 
76   // Optionally sets the preemption threshold for the ThreadX thread from 0
77   // through 31.
78   //
79   // Only priorities higher than this level (i.e. lower number) are allowed to
80   // preempt this thread. In other words this allows the thread to specify the
81   // priority ceiling for disabling preemption. Threads that have a higher
82   // priority than the ceiling are still allowed to preempt while those with
83   // less than the ceiling are not allowed to preempt.
84   //
85   // Not setting the preemption threshold or explicitly specifying a value
86   // equal to the priority disables preemption threshold.
87   //
88   // Time slicing is disabled while the preemption threshold is enabled, i.e.
89   // not equal to the priority, even if a time slice interval was specified.
90   //
91   // The preemption threshold can be adjusted at run time, this only sets the
92   // initial threshold.
93   //
94   // Precondition: preemption_threshold <= priority
set_preemption_threshold(UINT preemption_threshold)95   constexpr Options& set_preemption_threshold(UINT preemption_threshold) {
96     PW_DASSERT(preemption_threshold < PW_THREAD_THREADX_CONFIG_MIN_PRIORITY);
97     possible_preemption_threshold_ = preemption_threshold;
98     return *this;
99   }
100 
101   // Sets the number of ticks this thread is allowed to run before other ready
102   // threads of the same priority are given a chance to run.
103   //
104   // Time slicing is disabled while the preemption threshold is enabled, i.e.
105   // not equal to the priority, even if a time slice interval was specified.
106   //
107   // A value of TX_NO_TIME_SLICE (a value of 0) disables time-slicing of this
108   // thread.
109   //
110   // Using time slicing results in a slight amount of system overhead, threads
111   // with a unique priority should consider TX_NO_TIME_SLICE.
set_time_slice_interval(ULONG time_slice_interval)112   constexpr Options& set_time_slice_interval(ULONG time_slice_interval) {
113     time_slice_interval_ = time_slice_interval;
114     return *this;
115   }
116 
117   // Set the pre-allocated context (all memory needed to run a thread). Note
118   // that this is required for this thread creation backend! The Context can
119   // either be constructed with an externally provided span<ULONG> stack
120   // or the templated form of ContextWihtStack<kStackSizeWords> can be used.
set_context(Context & context)121   constexpr Options& set_context(Context& context) {
122     context_ = &context;
123     return *this;
124   }
125 
126  private:
127   friend Thread;
128   friend Context;
129   // Note that the default name may end up truncated due to
130   // PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN.
131   static constexpr char kDefaultName[] = "pw::Thread";
132 
name()133   const char* name() const { return name_; }
priority()134   UINT priority() const { return priority_; }
preemption_threshold()135   UINT preemption_threshold() const {
136     return possible_preemption_threshold_.value_or(priority_);
137   }
time_slice_interval()138   ULONG time_slice_interval() const { return time_slice_interval_; }
context()139   Context* context() const { return context_; }
140 
141   const char* name_ = kDefaultName;
142   UINT priority_ = config::kDefaultPriority;
143   // A default value cannot be used for the preemption threshold as it would
144   // have to be based on the selected priority.
145   std::optional<UINT> possible_preemption_threshold_ = std::nullopt;
146   ULONG time_slice_interval_ = config::kDefaultTimeSliceInterval;
147   Context* context_ = nullptr;
148 };
149 
150 }  // namespace pw::thread::threadx
151