aboutsummaryrefslogtreecommitdiff
path: root/pw_thread_threadx/public/pw_thread_threadx/options.h
blob: cdd3414fd25d8490ac49cdbe90bae20a9486c31b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 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(static_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(static_example_thread_context),
//     example_thread_function);
//
class Options : public thread::Options {
 public:
  constexpr Options() = default;
  constexpr Options(const Options&) = default;
  constexpr Options(Options&& other) = 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.
  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), see the
  // pw::thread::threadx::Context for more detail.
  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