blob: a96d1c37e36747e5593e629edf8ff8d3a659eeeb [file] [log] [blame]
// 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