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