SuperTinyKernel™ RTOS 1.08.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE > Class Template Referencefinal

Fixed-priority scheduling with Preemption-Threshold (PTS), modelled on Azure RTOS / ThreadX. Each task has a priority P and a threshold T with T >= P. While a task is running it can be preempted only by tasks whose priority is strictly greater than T. With T == P the task behaves like a normal fixed-priority task. More...

#include <stk_strategy_pthreshold.h>

Inheritance diagram for stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >:
Collaboration diagram for stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >:

Public Types

enum  EConfig {
  WEIGHT_API = 1 ,
  SLEEP_EVENT_API = 1 ,
  DEADLINE_MISSED_API = 0 ,
  PRIORITY_INHERITANCE_API = 1 ,
  NOSLEEP_YIELD_API = 1 ,
  TIMESLICE_API = (TIMESLICE ? 1 : 0)
}
 Compile-time capability flags reported to the kernel. More...

Public Member Functions

 SwitchStrategyPreemptionThreshold ()
 Construct an empty strategy.
STK_VIRT_DTOR ~SwitchStrategyPreemptionThreshold ()=default
 Destructor.
void AddTask (IKernelTask *task) override
 Add task to the runnable set at its priority level.
void RemoveTask (IKernelTask *task) override
 Remove task from whichever list it occupies (drops its hold if any).
IKernelTask * GetNext () override
 Select the next task to run.
IKernelTask * GetFirst () override
 First task in the managed set (highest ready level, else first sleeping).
size_t GetSize () const override
 Total number of tasks (runnable + sleeping).
void OnTaskSleep (IKernelTask *task) override
 Task went to sleep: leaves the runnable set and releases its hold.
void OnTaskWake (IKernelTask *task) override
 Task became runnable again; re-enters its priority level (not held).
void OnTaskWeightChange (IKernelTask *task, Weight old_weight) override
 Task weight changed (priority inheritance / restore): move to the new level.
bool OnTaskYield (IKernelTask *task) override
 Yield: hand the CPU to the next task of the same priority.
bool OnTaskTimeSlice (IKernelTask *task) override
 Time slice of the running task expired: rotate to the next task of the same priority.
virtual bool OnTaskDeadlineMissed (IKernelTask *task)
 Notification that a task has exceeded its HRT deadline; returns whether the strategy can recover without a hard fault.

Static Public Member Functions

static constexpr Weight MakeWeight (uint8_t priority, uint8_t threshold)
 Build a task weight from an STK priority and threshold.
static constexpr Weight FromThreadX (uint8_t tx_priority, uint8_t tx_threshold)
 Build a task weight from ThreadX numbers (0 = highest priority).
static uint8_t ChangeThreshold (IKernelService &service, TId tid, uint8_t priority, uint8_t threshold)
 Change the preemption-threshold of a task at run-time (tx_thread_preemption_change).

Protected Types

typedef uint8_t Priority
 Priority type.

Protected Member Functions

void AddActive (IKernelTask *task)
void RemoveActive (IKernelTask *task, const Priority prio)
void UpdateHold (IKernelTask *task, const Priority prio)
 Apply a threshold change to a runnable task that stays on the same level.

Static Protected Member Functions

static __stk_forceinline Priority DecodePriority (Weight weight)
static __stk_forceinline Priority GetTaskPriority (IKernelTask *task)
static __stk_forceinline Priority DecodeThreshold (Weight weight)
static __stk_forceinline Priority GetRawThreshold (IKernelTask *task)
 Configured threshold from the task's base weight (unaffected by priority inheritance).
static __stk_forceinline Priority GetTaskThreshold (IKernelTask *task)
static __stk_forceinline Priority GetHighestReadyPriority (uint32_t bitmap)

Private Member Functions

 STK_NONCOPYABLE_CLASS (SwitchStrategyPreemptionThreshold)

Private Attributes

IKernelTask::ListHeadType m_tasks [MAX_PRIORITIES]
 Runnable tasks per priority level.
IKernelTask::ListHeadType m_sleep
 Sleeping tasks.
uint32_t m_ready_bitmap
 Bit i set when m_tasks[i] is non-empty.
uint32_t m_held_bitmap
 Bit i set when m_held[i] is a task holding its preemption-threshold.
uint32_t m_advance_bitmap
 Bit i set: next GetNext() at level i advances the cursor (TIMESLICE only).
IKernelTask * m_running
 Task returned by the last GetNext() (nullptr if none or it left the runnable set).
IKernelTask * m_prev [MAX_PRIORITIES]
 Per-level round-robin cursor: last task returned by GetNext() (sticky mode: the selected task, kept until a rotation is requested).
IKernelTask * m_held [MAX_PRIORITIES]
 Per-level task currently holding its threshold (at most one per level, as in ThreadX).

Detailed Description

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
class stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >

Fixed-priority scheduling with Preemption-Threshold (PTS), modelled on Azure RTOS / ThreadX. Each task has a priority P and a threshold T with T >= P. While a task is running it can be preempted only by tasks whose priority is strictly greater than T. With T == P the task behaves like a normal fixed-priority task.

Template Parameters
MAX_PRIORITIESNumber of priority levels, [1, 32].
TIMESLICEtrue to enable time-slicing with per-task quanta for use with stk::KERNEL_TIMESLICE: GetNext() becomes sticky (the selected task of a level keeps running) and the level is rotated only by OnTaskTimeSlice(), OnTaskYield() or when the running task leaves the runnable set. false (default): fixed 1-tick round-robin on every GetNext().
Priority convention
STK convention is used: higher number = higher priority. ThreadX uses the opposite (0 = highest). Use FromThreadX() to convert ThreadX (priority, threshold) pairs.
Encoding in ITask::GetWeight()
Both values are packed into the task weight: (priority << 8) | threshold. Use MakeWeight() / FromThreadX() inside ITask::GetWeight(). Priority occupies the high bits so integer comparison of weights (as used by kernel priority inheritance) orders by priority first.
Scheduling rules
  • A task is held when it is selected while T > P. The hold lasts until the task sleeps, is removed, yields (see OnTaskYield()), or its threshold is lowered to its priority; if its priority changes (priority inheritance) the hold moves to the new level when that level's hold slot is free. A held task that is preempted by a task above its threshold remains held and is resumed as soon as no ready task is above its threshold (this mirrors ThreadX's behaviour where a preempted threshold-thread is resumed before ready tasks inside its protected band).
  • A held task is never time-sliced (ThreadX disables time-slicing for threads that use preemption-threshold): tasks of its own priority wait until it sleeps or yields.
  • Otherwise the highest ready priority level is served in round-robin: one tick each without TIMESLICE, or, with TIMESLICE, the running task keeps the CPU until its quantum (ITask::GetTimeSlice()) expires, it yields or it leaves the runnable set. Time-slicing only rotates tasks of the same priority, a lower priority level is never served instead.
Note
Uses WEIGHT_API (weight = encoded priority/threshold), SLEEP_EVENT_API, PRIORITY_INHERITANCE_API and NOSLEEP_YIELD_API, plus TIMESLICE_API if TIMESLICE is true.
Requires kernel support: IKernelTask::GetBaseWeight() and IKernelService::SetWeight() (run-time threshold change, see ChangeThreshold()) and the OnTaskYield() hook. With TIMESLICE the kernel must be built with stk::KERNEL_TIMESLICE, it charges the running task and calls OnTaskTimeSlice() when the quantum expires.
PRIORITY_INHERITANCE_API = 1: an inherited weight contributes only its priority (the waiter's threshold is ignored). The effective threshold of the owner is max(configured threshold, current priority), the configured threshold being read via IKernelTask::GetBaseWeight().
Yield() is handled by OnTaskYield() (tx_thread_relinquish semantics) in non-HRT modes.
Differences from ThreadX: STK priority numbering (higher = more important), at most 32 priority levels; without TIMESLICE the slice is fixed at 1 tick, with TIMESLICE (stk::KERNEL_TIMESLICE) the per-task quantum comes from ITask::GetTimeSlice().
With TIMESLICE, the quantum of a task can be changed at run-time with IKernelService::SetTimeSlice(). A task whose threshold is above its priority is held while it runs and is not time-sliced, use MakeWeight(p, p) for tasks which must be.
See also
SwitchStrategyPT32, SwitchStrategyPT32_TS, SwitchStrategyFixedPriority

Definition at line 83 of file stk_strategy_pthreshold.h.

Member Typedef Documentation

◆ Priority

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
typedef uint8_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::Priority
protected

Priority type.

Definition at line 437 of file stk_strategy_pthreshold.h.

Member Enumeration Documentation

◆ EConfig

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
enum stk::SwitchStrategyPreemptionThreshold::EConfig

Compile-time capability flags reported to the kernel.

Enumerator
WEIGHT_API 

GetWeight() carries the encoded priority and preemption-threshold.

SLEEP_EVENT_API 

Requires OnTaskSleep() / OnTaskWake() to maintain per-priority lists.

DEADLINE_MISSED_API 

Not used.

PRIORITY_INHERITANCE_API 

OnTaskWeightChange() events are handled.

NOSLEEP_YIELD_API 

OnTaskYield() events are handled.

TIMESLICE_API 

Sticky GetNext() and OnTaskTimeSlice() (see TIMESLICE template parameter).

Definition at line 89 of file stk_strategy_pthreshold.h.

90 {
91 WEIGHT_API = 1,
92 SLEEP_EVENT_API = 1,
96 TIMESLICE_API = (TIMESLICE ? 1 : 0)
97 };
Fixed-priority scheduling with Preemption-Threshold (PTS), modelled on Azure RTOS / ThreadX....
@ NOSLEEP_YIELD_API
OnTaskYield() events are handled.
@ SLEEP_EVENT_API
Requires OnTaskSleep() / OnTaskWake() to maintain per-priority lists.
@ WEIGHT_API
GetWeight() carries the encoded priority and preemption-threshold.
@ PRIORITY_INHERITANCE_API
OnTaskWeightChange() events are handled.
@ TIMESLICE_API
Sticky GetNext() and OnTaskTimeSlice() (see TIMESLICE template parameter).

Constructor & Destructor Documentation

◆ SwitchStrategyPreemptionThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::SwitchStrategyPreemptionThreshold ( )
inlineexplicit

Construct an empty strategy.

Definition at line 120 of file stk_strategy_pthreshold.h.

121 {
122 STK_STATIC_ASSERT_DESC(MAX_PRIORITIES <= 32U, "MAX_PRIORITIES exceeds 32-bit bitmap width");
123 }
#define STK_STATIC_ASSERT_DESC(X, DESC)
Compile-time assertion with a custom error description. Produces a compilation error if X is false.
Definition stk_defs.h:536
uint32_t m_ready_bitmap
Bit i set when m_tasks[i] is non-empty.
uint32_t m_held_bitmap
Bit i set when m_held[i] is a task holding its preemption-threshold.
IKernelTask * m_prev[MAX_PRIORITIES]
Per-level round-robin cursor: last task returned by GetNext() (sticky mode: the selected task,...
IKernelTask * m_running
Task returned by the last GetNext() (nullptr if none or it left the runnable set).
IKernelTask::ListHeadType m_sleep
Sleeping tasks.
IKernelTask::ListHeadType m_tasks[MAX_PRIORITIES]
Runnable tasks per priority level.
IKernelTask * m_held[MAX_PRIORITIES]
Per-level task currently holding its threshold (at most one per level, as in ThreadX).
uint32_t m_advance_bitmap
Bit i set: next GetNext() at level i advances the cursor (TIMESLICE only).

◆ ~SwitchStrategyPreemptionThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
STK_VIRT_DTOR stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::~SwitchStrategyPreemptionThreshold ( )
default

Destructor.

Note
MISRA deviation: [STK-DEV-005] Rule 10-3-2.

Member Function Documentation

◆ AddActive()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::AddActive ( IKernelTask * task)
inlineprotected

Definition at line 439 of file stk_strategy_pthreshold.h.

440 {
442
443 m_tasks[prio].LinkBack(task);
444
445 if (m_tasks[prio].GetSize() == 1U)
446 {
447 m_prev[prio] = task;
448 m_ready_bitmap |= (1U << prio);
449 }
450 }
static __stk_forceinline Priority GetTaskPriority(IKernelTask *task)
size_t GetSize() const override
Total number of tasks (runnable + sleeping).

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::AddTask(), stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWake(), and stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWeightChange().

Here is the caller graph for this function:

◆ AddTask()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::AddTask ( IKernelTask * task)
inlineoverridevirtual

Add task to the runnable set at its priority level.

Parameters
[in]taskTask to add. Its weight must be valid (priority < MAX_PRIORITIES, priority <= threshold < MAX_PRIORITIES).

Implements stk::ITaskSwitchStrategy.

Definition at line 134 of file stk_strategy_pthreshold.h.

135 {
136 STK_ASSERT(task != nullptr);
137 STK_ASSERT(task->GetHead() == nullptr);
141
143 const bool is_tail = (m_prev[prio] == m_tasks[prio].GetLast());
144
146
147 // non-sticky mode: if the cursor is on the tail, move it to the new task so that the next
148 // GetNext() returns the head instead of the new task (the new task waits for its turn),
149 // sticky mode (TIMESLICE): the cursor stays on the running task and the new task is
150 // appended behind it, the CPU is not taken over until the rotation is requested
151 if (is_tail && !TIMESLICE)
152 {
153 m_prev[prio] = task;
154 }
155 }
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
static __stk_forceinline Priority GetRawThreshold(IKernelTask *task)
Configured threshold from the task's base weight (unaffected by priority inheritance).

◆ ChangeThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
uint8_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::ChangeThreshold ( IKernelService & service,
TId tid,
uint8_t priority,
uint8_t threshold )
inlinestatic

Change the preemption-threshold of a task at run-time (tx_thread_preemption_change).

Parameters
[in]serviceKernel service (IKernelService::GetInstance()).
[in]tidTask id (IKernelService::GetTid() for the calling task).
[in]priorityThe task's configured STK priority (unchanged by this call).
[in]thresholdNew threshold, [priority, MAX_PRIORITIES - 1].
Returns
Previous threshold.
Note
If the task is the one currently running, a raised threshold protects it immediately; a threshold equal to the priority releases the protection. For a task that is not running the new threshold applies from its next selection. The task's time slice is not affected, but with TIMESLICE a task which is held (threshold above its priority) is not time-sliced while it holds.

Definition at line 427 of file stk_strategy_pthreshold.h.

428 {
431
433 }
static __stk_forceinline Priority DecodeThreshold(Weight weight)
static constexpr Weight MakeWeight(uint8_t priority, uint8_t threshold)
Build a task weight from an STK priority and threshold.

◆ DecodePriority()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
__stk_forceinline Priority stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::DecodePriority ( Weight weight)
inlinestaticprotected

Definition at line 519 of file stk_strategy_pthreshold.h.

520 {
521 return static_cast<Priority>((static_cast<uint32_t>(weight) >> 8) & 0xFFU);
522 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::GetTaskPriority(), and stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWeightChange().

Here is the caller graph for this function:

◆ DecodeThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
__stk_forceinline Priority stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::DecodeThreshold ( Weight weight)
inlinestaticprotected

Definition at line 529 of file stk_strategy_pthreshold.h.

530 {
531 return static_cast<Priority>(static_cast<uint32_t>(weight) & 0xFFU);
532 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::ChangeThreshold(), and stk::SwitchStrategyPreemptionThreshold< 32 >::GetRawThreshold().

Here is the caller graph for this function:

◆ FromThreadX()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
constexpr Weight stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::FromThreadX ( uint8_t tx_priority,
uint8_t tx_threshold )
inlinestaticconstexpr

Build a task weight from ThreadX numbers (0 = highest priority).

Parameters
[in]tx_priorityThreadX priority, [0, MAX_PRIORITIES - 1].
[in]tx_thresholdThreadX preemption-threshold, [0, tx_priority].

Definition at line 112 of file stk_strategy_pthreshold.h.

113 {
114 return MakeWeight(static_cast<uint8_t>((MAX_PRIORITIES - 1U) - tx_priority),
115 static_cast<uint8_t>((MAX_PRIORITIES - 1U) - tx_threshold));
116 }

◆ GetFirst()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask * stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetFirst ( )
inlineoverridevirtual

First task in the managed set (highest ready level, else first sleeping).

Implements stk::ITaskSwitchStrategy.

Definition at line 242 of file stk_strategy_pthreshold.h.

243 {
244 STK_ASSERT(GetSize() != 0U);
245
246 IKernelTask *first_task = nullptr;
247
248 if (m_ready_bitmap == 0U)
249 {
250 first_task = (*m_sleep.GetFirst());
251 }
252 else
253 {
255 }
256
257 return first_task;
258 }
static __stk_forceinline Priority GetHighestReadyPriority(uint32_t bitmap)

◆ GetHighestReadyPriority()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
__stk_forceinline Priority stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetHighestReadyPriority ( uint32_t bitmap)
inlinestaticprotected

Definition at line 551 of file stk_strategy_pthreshold.h.

552 {
553 return static_cast<Priority>(31U - CountLeadingZeros(bitmap));
554 }
static uint32_t CountLeadingZeros(const uint32_t value) noexcept
Count leading zeros.
Definition stk_defs.h:783

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::GetFirst(), and stk::SwitchStrategyPreemptionThreshold< 32 >::GetNext().

Here is the caller graph for this function:

◆ GetNext()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask * stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetNext ( )
inlineoverridevirtual

Select the next task to run.

Returns
Task to run, or nullptr if nothing is runnable.
Note
1) Find the highest ready priority hi. 2) If a task is held (the highest-priority holder H) and hi <= threshold(H), H keeps/resumes the CPU. 3) Otherwise round-robin inside level hi; if the chosen task has threshold > priority it becomes held.
In round-robin mode (TIMESLICE = false) the cursor of the level advances on every call. In sticky mode (TIMESLICE = true) the cursor advances only if a rotation was requested for the level (OnTaskYield(), OnTaskTimeSlice() or the removal of the task the cursor was on), otherwise the same task is returned.

Implements stk::ITaskSwitchStrategy.

Definition at line 187 of file stk_strategy_pthreshold.h.

188 {
189 IKernelTask *next = nullptr;
190
191 if (m_ready_bitmap != 0U)
192 {
194
195 if (m_held_bitmap != 0U)
196 {
198 STK_ASSERT(holder != nullptr);
199
200 if (hi <= GetTaskThreshold(holder))
201 {
202 next = holder;
203 }
204 }
205
206 if (next == nullptr)
207 {
208 bool advance = true;
209
211 {
212 // sticky: the cursor moves only when a rotation was requested for this level
213 advance = ((m_advance_bitmap & (1U << hi)) != 0U);
214 m_advance_bitmap &= ~(1U << hi);
215 }
216
217 if (advance)
218 {
219 next = (*m_prev[hi]->GetNext());
220 m_prev[hi] = next;
221 }
222 else
223 {
224 next = m_prev[hi];
225 }
226
227 if (GetTaskThreshold(next) > hi)
228 {
229 m_held[hi] = next;
230 m_held_bitmap |= (1U << hi);
231 }
232 }
233 }
234
235 m_running = next;
236
237 return next;
238 }
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:489
static __stk_forceinline Priority GetTaskThreshold(IKernelTask *task)

◆ GetRawThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
__stk_forceinline Priority stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetRawThreshold ( IKernelTask * task)
inlinestaticprotected

Configured threshold from the task's base weight (unaffected by priority inheritance).

Definition at line 535 of file stk_strategy_pthreshold.h.

536 {
537 return DecodeThreshold(task->GetBaseWeight());
538 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::AddTask(), and stk::SwitchStrategyPreemptionThreshold< 32 >::GetTaskThreshold().

Here is the caller graph for this function:

◆ GetSize()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
size_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetSize ( ) const
inlineoverridevirtual

Total number of tasks (runnable + sleeping).

Implements stk::ITaskSwitchStrategy.

Definition at line 262 of file stk_strategy_pthreshold.h.

263 {
264 size_t total = m_sleep.GetSize();
265 for (Priority i = 0U; i < MAX_PRIORITIES; ++i)
266 {
267 total += m_tasks[i].GetSize();
268 }
269
270 return total;
271 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::AddActive(), stk::SwitchStrategyPreemptionThreshold< 32 >::GetFirst(), and stk::SwitchStrategyPreemptionThreshold< 32 >::RemoveTask().

Here is the caller graph for this function:

◆ GetTaskPriority()

◆ GetTaskThreshold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
__stk_forceinline Priority stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::GetTaskThreshold ( IKernelTask * task)
inlinestaticprotected

Effective threshold = max(configured threshold, current priority). While the task inherits a higher priority its protected band is raised to at least that priority but never loses the configured threshold.

Definition at line 543 of file stk_strategy_pthreshold.h.

544 {
547
548 return (thr > prio ? thr : prio);
549 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::GetNext(), stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWeightChange(), and stk::SwitchStrategyPreemptionThreshold< 32 >::UpdateHold().

Here is the caller graph for this function:

◆ MakeWeight()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
constexpr Weight stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::MakeWeight ( uint8_t priority,
uint8_t threshold )
inlinestaticconstexpr

Build a task weight from an STK priority and threshold.

Parameters
[in]priorityTask priority, [0, MAX_PRIORITIES - 1], higher = more important.
[in]thresholdPreemption-threshold, [priority, MAX_PRIORITIES - 1].

Definition at line 103 of file stk_strategy_pthreshold.h.

104 {
105 return static_cast<Weight>((static_cast<Weight>(priority) << 8) | static_cast<Weight>(threshold));
106 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::FromThreadX().

Here is the caller graph for this function:

◆ OnTaskDeadlineMissed()

virtual bool stk::ITaskSwitchStrategy::OnTaskDeadlineMissed ( IKernelTask * task)
inlinevirtualinherited

Notification that a task has exceeded its HRT deadline; returns whether the strategy can recover without a hard fault.

Parameters
[in]taskThe task whose deadline was missed. Must not be nullptr.
Returns
true — the strategy has absorbed the overrun (e.g. by escalating its scheduling mode): the kernel must not call HrtHardFailDeadline() for this tick. false — the strategy cannot recover: the kernel must call HrtHardFailDeadline() as normal.
Note
Budget Overrun API. Called by the kernel from UpdateTaskState() within a tick, after GetNext() has already been called for that tick. Only invoked when DEADLINE_MISSED_API == 1 in the concrete strategy's EConfig. Strategies that set DEADLINE_MISSED_API = 0 do not need to implement this method; the kernel will not call it and will proceed directly to HrtHardFailDeadline().
Returning true carries no implicit side-effects on task sleep state or duration counters — normal tick-driven scheduling remains responsible for those. This call only communicates "do not hard-fault this tick."
The base implementation returns false (unrecoverable), which is the correct default for strategies that do not implement overrun recovery.

Definition at line 1487 of file stk_common.h.

1488 {
1489 STK_UNUSED(task);
1490 return false;
1491 }
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715

References STK_UNUSED.

◆ OnTaskSleep()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::OnTaskSleep ( IKernelTask * task)
inlineoverridevirtual

Task went to sleep: leaves the runnable set and releases its hold.

Note
In sticky mode (TIMESLICE) if the task was the one the level cursor was on, the next peer is selected by the following GetNext().

Implements stk::ITaskSwitchStrategy.

Definition at line 277 of file stk_strategy_pthreshold.h.

278 {
279 STK_ASSERT(task != nullptr);
280 STK_ASSERT(task->IsSleeping());
281 STK_ASSERT(task->GetHead() == &m_tasks[GetTaskPriority(task)]);
282
284 m_sleep.LinkBack(task);
285 }
void RemoveActive(IKernelTask *task, const Priority prio)

◆ OnTaskTimeSlice()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
bool stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::OnTaskTimeSlice ( IKernelTask * task)
inlineoverridevirtual

Time slice of the running task expired: rotate to the next task of the same priority.

Parameters
[in]taskThe running task.
Returns
true if the level was rotated; false if the task has no same-priority peer, is held by its preemption-threshold (held tasks are never time-sliced, as in ThreadX), is not in a runnable list, or the strategy is not a TIMESLICE one.
Note
A held task is never rotated, so unlike OnTaskYield() its hold is never released here. When false is returned the task simply keeps running, the kernel has already reloaded its slice.

Reimplemented from stk::ITaskSwitchStrategy.

Definition at line 390 of file stk_strategy_pthreshold.h.

391 {
392 bool rotated = false;
393
395 {
396 STK_ASSERT(task != nullptr);
397
399
400 // rotation requires a same-priority peer: a lone task simply continues (with a fresh slice
401 // reloaded by the kernel), no rotation request is left pending for the level
402 if ((prio < MAX_PRIORITIES) && (task->GetHead() == &m_tasks[prio]) && (m_held[prio] != task) &&
403 (m_tasks[prio].GetSize() > 1U))
404 {
405 m_prev[prio] = task;
406 rotated = true;
407
408 m_advance_bitmap |= (1U << prio);
409 }
410 }
411
412 return rotated;
413 }

◆ OnTaskWake()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::OnTaskWake ( IKernelTask * task)
inlineoverridevirtual

Task became runnable again; re-enters its priority level (not held).

Note
It is appended behind the other tasks of its level, in sticky mode (TIMESLICE) it does not take the CPU from the running peer before that task's rotation.

Implements stk::ITaskSwitchStrategy.

Definition at line 291 of file stk_strategy_pthreshold.h.

292 {
293 STK_ASSERT(task != nullptr);
294 STK_ASSERT(!task->IsSleeping());
295 STK_ASSERT(task->GetHead() == &m_sleep);
296
297 m_sleep.Unlink(task);
299 }

◆ OnTaskWeightChange()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::OnTaskWeightChange ( IKernelTask * task,
Weight old_weight )
inlineoverridevirtual

Task weight changed (priority inheritance / restore): move to the new level.

Note
A hold is migrated to the new level if the effective threshold is still above the new priority and the level's hold slot is free; otherwise it is released.

Reimplemented from stk::ITaskSwitchStrategy.

Definition at line 305 of file stk_strategy_pthreshold.h.

306 {
309
312
313 if (task->GetHead() != &m_sleep)
314 {
315 STK_ASSERT(task->GetHead() == &m_tasks[old_prio]);
316
317 if (old_prio == new_prio)
318 {
319 // threshold-only change (IKernelService::SetWeight): no relinking needed
321 }
322 else
323 {
324 const bool was_held = (m_held[old_prio] == task);
325
328
329 // migrate the hold to the new level if the task still has a protected band
330 // and the level's (single) hold slot is free
331 if (was_held && (GetTaskThreshold(task) > new_prio) && (m_held[new_prio] == nullptr))
332 {
334 m_held_bitmap |= (1U << new_prio);
335 }
336 }
337 }
338 }
void UpdateHold(IKernelTask *task, const Priority prio)
Apply a threshold change to a runnable task that stays on the same level.

◆ OnTaskYield()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
bool stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::OnTaskYield ( IKernelTask * task)
inlineoverridevirtual

Yield: hand the CPU to the next task of the same priority.

Parameters
[in]taskThe yielding (running) task.
Returns
true: the task stays runnable and is not put to sleep by the kernel; false if the task is not in a runnable list (kernel falls back to a sleep-yield).
Note
The cursor of the task's level is set to the task so that GetNext() returns its next peer (or the task itself if it has none: it simply continues). The highest ready level does not change, therefore no lower-priority task runs.
The yielder's preemption-threshold hold is released so peers are not blocked by it. Ready tasks above its priority but within its former threshold are no longer blocked either and may run.
In sticky mode (TIMESLICE) a rotation of the level is requested explicitly, the kernel also restarts the time slice of the yielding task (tx_thread_relinquish semantics).

Reimplemented from stk::ITaskSwitchStrategy.

Definition at line 354 of file stk_strategy_pthreshold.h.

355 {
356 STK_ASSERT(task != nullptr);
357
358 bool handled = false;
360
361 if ((prio < MAX_PRIORITIES) && (task->GetHead() == &m_tasks[prio]))
362 {
363 if (m_held[prio] == task)
364 {
365 m_held[prio] = nullptr;
366 m_held_bitmap &= ~(1U << prio);
367 }
368
369 m_prev[prio] = task;
370 handled = true;
371
373 {
374 m_advance_bitmap |= (1U << prio);
375 }
376 }
377
378 return handled;
379 }

◆ RemoveActive()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::RemoveActive ( IKernelTask * task,
const Priority prio )
inlineprotected

Definition at line 452 of file stk_strategy_pthreshold.h.

453 {
454 IKernelTask *const next = (*task->GetNext());
455
456 m_tasks[prio].Unlink(task);
457
458 if (m_running == task)
459 {
460 m_running = nullptr;
461 }
462
463 // release preemption-threshold hold
464 if (m_held[prio] == task)
465 {
466 m_held[prio] = nullptr;
467 m_held_bitmap &= ~(1U << prio);
468 }
469
470 if (next == task)
471 {
472 m_prev[prio] = nullptr;
473 m_ready_bitmap &= ~(1U << prio);
474
476 {
477 m_advance_bitmap &= ~(1U << prio);
478 }
479 }
480 else if (m_prev[prio] == task)
481 {
482 // cursor was on the removed task: step back so GetNext() returns its successor;
483 // otherwise leave the rotation untouched
484 m_prev[prio] = (*next->GetPrev());
485
487 {
488 // sticky mode: the successor must run next
489 m_advance_bitmap |= (1U << prio);
490 }
491 }
492 }
IKernelTask * GetNext() override
Select the next task to run.

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskSleep(), stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWeightChange(), and stk::SwitchStrategyPreemptionThreshold< 32 >::RemoveTask().

Here is the caller graph for this function:

◆ RemoveTask()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::RemoveTask ( IKernelTask * task)
inlineoverridevirtual

Remove task from whichever list it occupies (drops its hold if any).

Implements stk::ITaskSwitchStrategy.

Definition at line 159 of file stk_strategy_pthreshold.h.

160 {
161 STK_ASSERT(task != nullptr);
162 STK_ASSERT(GetSize() != 0U);
163 STK_ASSERT((task->GetHead() == &m_tasks[GetTaskPriority(task)]) || (task->GetHead() == &m_sleep));
164
165 if (task->GetHead() == &m_sleep)
166 {
167 m_sleep.Unlink(task);
168 }
169 else
170 {
172 }
173 }

◆ STK_NONCOPYABLE_CLASS()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::STK_NONCOPYABLE_CLASS ( SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE > )
private

◆ UpdateHold()

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
void stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::UpdateHold ( IKernelTask * task,
const Priority prio )
inlineprotected

Apply a threshold change to a runnable task that stays on the same level.

Note
Raised threshold on the running task: it becomes held now. Threshold not above the priority: any hold is released. Other tasks pick the hold up when next selected.

Definition at line 498 of file stk_strategy_pthreshold.h.

499 {
501 {
502 if ((task == m_running) && (m_held[prio] == nullptr))
503 {
504 m_held[prio] = task;
505 m_held_bitmap |= (1U << prio);
506 }
507 }
508 else if (m_held[prio] == task)
509 {
510 m_held[prio] = nullptr;
511 m_held_bitmap &= ~(1U << prio);
512 }
513 else
514 {
515 // nothing to update
516 }
517 }

Referenced by stk::SwitchStrategyPreemptionThreshold< 32 >::OnTaskWeightChange().

Here is the caller graph for this function:

Member Data Documentation

◆ m_advance_bitmap

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
uint32_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_advance_bitmap
private

Bit i set: next GetNext() at level i advances the cursor (TIMESLICE only).

Definition at line 563 of file stk_strategy_pthreshold.h.

◆ m_held

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask* stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_held[MAX_PRIORITIES]
private

Per-level task currently holding its threshold (at most one per level, as in ThreadX).

Definition at line 566 of file stk_strategy_pthreshold.h.

◆ m_held_bitmap

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
uint32_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_held_bitmap
private

Bit i set when m_held[i] is a task holding its preemption-threshold.

Definition at line 562 of file stk_strategy_pthreshold.h.

◆ m_prev

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask* stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_prev[MAX_PRIORITIES]
private

Per-level round-robin cursor: last task returned by GetNext() (sticky mode: the selected task, kept until a rotation is requested).

Definition at line 565 of file stk_strategy_pthreshold.h.

◆ m_ready_bitmap

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
uint32_t stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_ready_bitmap
private

Bit i set when m_tasks[i] is non-empty.

Definition at line 561 of file stk_strategy_pthreshold.h.

◆ m_running

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask* stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_running
private

Task returned by the last GetNext() (nullptr if none or it left the runnable set).

Definition at line 564 of file stk_strategy_pthreshold.h.

◆ m_sleep

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask::ListHeadType stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_sleep
private

Sleeping tasks.

Definition at line 560 of file stk_strategy_pthreshold.h.

◆ m_tasks

template<uint8_t MAX_PRIORITIES, bool TIMESLICE = false>
IKernelTask::ListHeadType stk::SwitchStrategyPreemptionThreshold< MAX_PRIORITIES, TIMESLICE >::m_tasks[MAX_PRIORITIES]
private

Runnable tasks per priority level.

Definition at line 559 of file stk_strategy_pthreshold.h.


The documentation for this class was generated from the following file: