• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // pw::thread::Options for ThreadX.
27 //
28 // Example usage:
29 //
30 //   // Uses the default priority and time slice interval (which may be
31 //   // disabled), but specifies a custom name and pre-allocated context.
32 //   // Note that the preemption threshold is disabled by default.
33 //   pw::thread::Thread example_thread(
34 //     pw::thread::threadx::Options()
35 //         .set_name("example_thread"),
36 //         .set_context(example_thread_context),
37 //     example_thread_function);
38 //
39 //   // Specifies the name, priority, time slice interval, and pre-allocated
40 //   // context, but does not use a preemption threshold.
41 //   pw::thread::Thread static_example_thread(
42 //     pw::thread::threadx::Options()
43 //         .set_name("static_example_thread")
44 //         .set_priority(kFooPriority)
45 //         .set_time_slice_interval(1)
46 //         .set_context(example_thread_context),
47 //     example_thread_function);
48 //
49 class Options : public thread::Options {
50  public:
Options()51   constexpr Options() {}
52   constexpr Options(const Options&) = default;
53   constexpr Options(Options&&) = default;
54 
55   // Sets the name for the ThreadX thread, note that this will be deep copied
56   // into the context and may be truncated based on
57   // PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN.
set_name(const char * name)58   constexpr Options& set_name(const char* name) {
59     name_ = name;
60     return *this;
61   }
62 
63   // Sets the priority for the ThreadX thread from 0 through 31, where a value
64   // of 0 represents the highest priority, see ThreadX tx_thread_create for
65   // more detail.
66   //
67   // Precondition: priority <= PW_THREAD_THREADX_CONFIG_MIN_PRIORITY
set_priority(UINT priority)68   constexpr Options& set_priority(UINT priority) {
69     PW_DASSERT(priority <= PW_THREAD_THREADX_CONFIG_MIN_PRIORITY);
70     priority_ = priority;
71     return *this;
72   }
73 
74   // Optionally sets the preemption threshold for the ThreadX thread from 0
75   // through 31.
76   //
77   // Only priorities higher than this level (i.e. lower number) are allowed to
78   // preempt this thread. In other words this allows the thread to specify the
79   // priority ceiling for disabling preemption. Threads that have a higher
80   // priority than the ceiling are still allowed to preempt while those with
81   // less than the ceiling are not allowed to preempt.
82   //
83   // Not setting the preemption threshold or explicitly specifying a value
84   // equal to the priority disables preemption threshold.
85   //
86   // Time slicing is disabled while the preemption threshold is enabled, i.e.
87   // not equal to the priority, even if a time slice interval was specified.
88   //
89   // The preemption threshold can be adjusted at run time, this only sets the
90   // initial threshold.
91   //
92   // Precondition: preemption_threshold <= priority
set_preemption_threshold(UINT preemption_threshold)93   constexpr Options& set_preemption_threshold(UINT preemption_threshold) {
94     PW_DASSERT(preemption_threshold < PW_THREAD_THREADX_CONFIG_MIN_PRIORITY);
95     possible_preemption_threshold_ = preemption_threshold;
96     return *this;
97   }
98 
99   // Sets the number of ticks this thread is allowed to run before other ready
100   // threads of the same priority are given a chance to run.
101   //
102   // Time slicing is disabled while the preemption threshold is enabled, i.e.
103   // not equal to the priority, even if a time slice interval was specified.
104   //
105   // A value of TX_NO_TIME_SLICE (a value of 0) disables time-slicing of this
106   // thread.
107   //
108   // Using time slicing results in a slight amount of system overhead, threads
109   // with a unique priority should consider TX_NO_TIME_SLICE.
set_time_slice_interval(ULONG time_slice_interval)110   constexpr Options& set_time_slice_interval(ULONG time_slice_interval) {
111     time_slice_interval_ = time_slice_interval;
112     return *this;
113   }
114 
115   // Set the pre-allocated context (all memory needed to run a thread). Note
116   // that this is required for this thread creation backend! The Context can
117   // either be constructed with an externally provided span<ULONG> stack
118   // or the templated form of ContextWihtStack<kStackSizeWords> can be used.
set_context(Context & context)119   constexpr Options& set_context(Context& context) {
120     context_ = &context;
121     return *this;
122   }
123 
124  private:
125   friend thread::Thread;
126   // Note that the default name may end up truncated due to
127   // PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN.
128   static constexpr char kDefaultName[] = "pw::Thread";
129 
name()130   const char* name() const { return name_; }
priority()131   UINT priority() const { return priority_; }
preemption_threshold()132   UINT preemption_threshold() const {
133     return possible_preemption_threshold_.value_or(priority_);
134   }
time_slice_interval()135   ULONG time_slice_interval() const { return time_slice_interval_; }
context()136   Context* context() const { return context_; }
137 
138   const char* name_ = kDefaultName;
139   UINT priority_ = config::kDefaultPriority;
140   // A default value cannot be used for the preemption threshold as it would
141   // have to be based on the selected priority.
142   std::optional<UINT> possible_preemption_threshold_ = std::nullopt;
143   ULONG time_slice_interval_ = config::kDefaultTimeSliceInterval;
144   Context* context_ = nullptr;
145 };
146 
147 }  // namespace pw::thread::threadx
148