| // Copyright 2021 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| #pragma once |
| |
| #include "pw_assert/assert.h" |
| #include "pw_thread/thread.h" |
| #include "pw_thread_threadx/config.h" |
| #include "pw_thread_threadx/context.h" |
| #include "tx_api.h" |
| |
| namespace pw::thread::threadx { |
| |
| // pw::thread::Options for ThreadX. |
| // |
| // Example usage: |
| // |
| // // Uses the default priority and time slice interval (which may be |
| // // disabled), but specifies a custom name and pre-allocated context. |
| // // Note that the preemption threshold is disabled by default. |
| // pw::thread::Thread example_thread( |
| // pw::thread::threadx::Options() |
| // .set_name("example_thread"), |
| // .set_context(example_thread_context), |
| // example_thread_function); |
| // |
| // // Specifies the name, priority, time slice interval, and pre-allocated |
| // // context, but does not use a preemption threshold. |
| // pw::thread::Thread static_example_thread( |
| // pw::thread::threadx::Options() |
| // .set_name("static_example_thread") |
| // .set_priority(kFooPriority) |
| // .set_time_slice_interval(1) |
| // .set_context(example_thread_context), |
| // example_thread_function); |
| // |
| class Options : public thread::Options { |
| public: |
| constexpr Options() {} |
| constexpr Options(const Options&) = default; |
| constexpr Options(Options&&) = default; |
| |
| // 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. |
| constexpr Options& set_name(const char* name) { |
| name_ = name; |
| return *this; |
| } |
| |
| // 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; |
| return *this; |
| } |
| |
| // 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 |
| constexpr Options& set_preemption_threshold(UINT preemption_threshold) { |
| PW_DASSERT(preemption_threshold < PW_THREAD_THREADX_CONFIG_MIN_PRIORITY); |
| possible_preemption_threshold_ = preemption_threshold; |
| return *this; |
| } |
| |
| // 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. |
| constexpr Options& set_time_slice_interval(ULONG time_slice_interval) { |
| time_slice_interval_ = time_slice_interval; |
| return *this; |
| } |
| |
| // 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 span<ULONG> stack |
| // or the templated form of ContextWihtStack<kStackSizeWords> can be used. |
| constexpr Options& set_context(Context& context) { |
| context_ = &context; |
| return *this; |
| } |
| |
| private: |
| friend thread::Thread; |
| // Note that the default name may end up truncated due to |
| // PW_THREAD_THREADX_CONFIG_MAX_THREAD_NAME_LEN. |
| static constexpr char kDefaultName[] = "pw::Thread"; |
| |
| const char* name() const { return name_; } |
| UINT priority() const { return priority_; } |
| UINT preemption_threshold() const { |
| return possible_preemption_threshold_.value_or(priority_); |
| } |
| ULONG time_slice_interval() const { return time_slice_interval_; } |
| Context* context() const { return context_; } |
| |
| const char* name_ = kDefaultName; |
| UINT priority_ = config::kDefaultPriority; |
| // A default value cannot be used for the preemption threshold as it would |
| // have to be based on the selected priority. |
| std::optional<UINT> possible_preemption_threshold_ = std::nullopt; |
| ULONG time_slice_interval_ = config::kDefaultTimeSliceInterval; |
| Context* context_ = nullptr; |
| }; |
| |
| } // namespace pw::thread::threadx |