SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::SwitchStrategySmoothWeightedRoundRobin Class Referencefinal

Smooth Weighted Round-Robin (SWRR) task-switching strategy: distributes CPU time proportionally to per-task weights while avoiding execution bursts by spreading selections evenly over time. More...

#include <stk_strategy_swrrobin.h>

Inheritance diagram for stk::SwitchStrategySmoothWeightedRoundRobin:
Collaboration diagram for stk::SwitchStrategySmoothWeightedRoundRobin:

Public Types

enum  EConfig {
  WEIGHT_API = 1 ,
  SLEEP_EVENT_API = 1 ,
  DEADLINE_MISSED_API = 0 ,
  PRIORITY_INHERITANCE_API = 0
}
 Compile-time capability flags reported to the kernel. More...

Public Member Functions

 SwitchStrategySmoothWeightedRoundRobin ()
 Construct an empty strategy with no tasks and a zero total weight.
STK_VIRT_DTOR ~SwitchStrategySmoothWeightedRoundRobin ()=default
 Destructor.
void AddTask (IKernelTask *task) override
 Add task to the runnable set.
void RemoveTask (IKernelTask *task) override
 Remove task from whichever list it currently occupies.
IKernelTaskGetNext () override
 Select and return the next task to run, applying one step of the SWRR algorithm.
IKernelTaskGetFirst () override
 Get first task in the managed set (used by the kernel for initial scheduling).
size_t GetSize () const override
 Get the total number of tasks managed by this strategy.
void OnTaskSleep (IKernelTask *task) override
 Notification that a task has entered the sleeping state.
void OnTaskWake (IKernelTask *task) override
 Notification that a task has become runnable again.
virtual bool OnTaskDeadlineMissed (IKernelTask *task)
 Notification that a task has exceeded its HRT deadline; returns whether the strategy can recover without a hard fault.
virtual void OnTaskWeightChange (IKernelTask *task, Weight old_weight)
 Notification that a runnable task's scheduling weight has changed.

Private Member Functions

 STK_NONCOPYABLE_CLASS (SwitchStrategySmoothWeightedRoundRobin)
void AddActive (IKernelTask *task)
 Append task to m_tasks and update the total weight.
void RemoveActive (IKernelTask *task)
 Remove task from m_tasks and update the total weight.

Private Attributes

IKernelTask::ListHeadType m_tasks
 Runnable tasks eligible for scheduling.
IKernelTask::ListHeadType m_sleep
 Sleeping (blocked) tasks not eligible for scheduling.
int32_t m_total_weight
 Sum of static weights (GetWeight()) of all tasks currently in m_tasks. Sleeping tasks are excluded. Updated on every AddActive() / RemoveActive() call. Used as the post-selection deduction amount in GetNext() and as the wake-up boost value in OnTaskWake().

Detailed Description

Smooth Weighted Round-Robin (SWRR) task-switching strategy: distributes CPU time proportionally to per-task weights while avoiding execution bursts by spreading selections evenly over time.

This is an improved variant of standard Weighted Round-Robin.

See also
https://en.wikipedia.org/wiki/Weighted_round_robin
Algorithm
Each task carries two weight values:
  • Static weight (GetWeight()): configured by the application via ITask::GetWeight(). Defines the task's desired CPU share relative to other tasks. Must be a positive 24-bit integer (1 .. 0x7FFFFF). A task with weight 3 receives three times as much CPU time as one with weight 1.
  • Dynamic (current) weight (GetCurrentWeight() / SetCurrentWeight()): modified each scheduling step by the algorithm below. Starts at 0 when a task is added.

On every call to GetNext() (once per kernel tick):

  1. For every runnable task: current_weight += static_weight
  2. Select the task with the highest current_weight as the next to run.
  3. For the selected task only: current_weight -= total_weight_sum (where total_weight_sum is the sum of static weights of all runnable tasks).

Over time this produces fair, proportional CPU distribution without consecutive bursts.

Wake-up priority boost
When a sleeping task is woken (OnTaskWake()), its current_weight is set to total_weight_sum so it is selected on the very next tick. This prevents starvation of tasks that had been blocking on I/O or synchronization objects.
Note
Requires the Weight API (WEIGHT_API = 1): the kernel must provide GetWeight(), GetCurrentWeight(), and SetCurrentWeight() on each kernel task.
Requires the kernel Sleep API (SLEEP_EVENT_API = 1): the kernel must call OnTaskSleep() and OnTaskWake() to keep m_total_weight consistent as tasks enter and leave the runnable set.
GetNext() iterates over all runnable tasks — O(n) per tick. For large task counts the constant factor is small (integer arithmetic only), but this should be considered when sizing TASKS_MAX on severely constrained targets.
See also
SwitchStrategySWRR, ITaskSwitchStrategy, ITask::GetWeight, IKernelTask::GetWeight

Definition at line 62 of file stk_strategy_swrrobin.h.

Member Enumeration Documentation

◆ EConfig

Compile-time capability flags reported to the kernel.

Enumerator
WEIGHT_API 

This strategy uses per-task static and dynamic weights; the kernel must expose the Weight API on each IKernelTask.

SLEEP_EVENT_API 

This strategy requires OnTaskSleep() / OnTaskWake() events to keep m_total_weight accurate as tasks move between the runnable and sleeping sets.

DEADLINE_MISSED_API 

This strategy does not use OnTaskDeadlineMissed() events.

PRIORITY_INHERITANCE_API 

This strategy does not require Priority Inheritance and OnTaskPriorityChange() events.

Definition at line 68 of file stk_strategy_swrrobin.h.

69 {
70 WEIGHT_API = 1,
71 SLEEP_EVENT_API = 1,
74 };
@ PRIORITY_INHERITANCE_API
This strategy does not require Priority Inheritance and OnTaskPriorityChange() events.
@ SLEEP_EVENT_API
This strategy requires OnTaskSleep() / OnTaskWake() events to keep m_total_weight accurate as tasks m...
@ DEADLINE_MISSED_API
This strategy does not use OnTaskDeadlineMissed() events.
@ WEIGHT_API
This strategy uses per-task static and dynamic weights; the kernel must expose the Weight API on each...

Constructor & Destructor Documentation

◆ SwitchStrategySmoothWeightedRoundRobin()

stk::SwitchStrategySmoothWeightedRoundRobin::SwitchStrategySmoothWeightedRoundRobin ( )
inlineexplicit

Construct an empty strategy with no tasks and a zero total weight.

Definition at line 78 of file stk_strategy_swrrobin.h.

79 {}
int32_t m_total_weight
Sum of static weights (GetWeight()) of all tasks currently in m_tasks. Sleeping tasks are excluded....
IKernelTask::ListHeadType m_tasks
Runnable tasks eligible for scheduling.
IKernelTask::ListHeadType m_sleep
Sleeping (blocked) tasks not eligible for scheduling.

References m_sleep, m_tasks, and m_total_weight.

Referenced by STK_NONCOPYABLE_CLASS().

Here is the caller graph for this function:

◆ ~SwitchStrategySmoothWeightedRoundRobin()

STK_VIRT_DTOR stk::SwitchStrategySmoothWeightedRoundRobin::~SwitchStrategySmoothWeightedRoundRobin ( )
default

Destructor.

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

References STK_VIRT_DTOR.

Member Function Documentation

◆ AddActive()

void stk::SwitchStrategySmoothWeightedRoundRobin::AddActive ( IKernelTask * task)
inlineprivate

Append task to m_tasks and update the total weight.

Parameters
[in]taskTask to make runnable.
Note
Increments m_total_weight by the task's static weight so that the post-selection deduction in GetNext() remains correct.

Definition at line 246 of file stk_strategy_swrrobin.h.

247 {
248 m_tasks.LinkBack(task);
249 m_total_weight += task->GetWeight();
250 }

References stk::IKernelTask::GetWeight(), m_tasks, and m_total_weight.

Referenced by AddTask(), and OnTaskWake().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddTask()

void stk::SwitchStrategySmoothWeightedRoundRobin::AddTask ( IKernelTask * task)
inlineoverridevirtual

Add task to the runnable set.

Parameters
[in]taskTask to add. Must not be nullptr.
Note
The task's static weight (GetWeight()) is validated: must be a positive 24-bit integer [1, 0x7FFFFF]. Negative or zero weights would break the algorithm invariant. Values above 0x7FFFFF would risk int32_t overflow in the accumulated current-weight arithmetic.
The dynamic weight (current weight) is reset to 0 before the task is added to the runnable set. This gives all newly-added tasks an equal starting position in the selection cycle.
Delegates to AddActive() which also increments m_total_weight.

Implements stk::ITaskSwitchStrategy.

Definition at line 97 of file stk_strategy_swrrobin.h.

98 {
99 STK_ASSERT(task != nullptr);
100 STK_ASSERT((task->GetWeight() > 0) && (task->GetWeight() <= 0x7FFFFF)); // must not be negative, max 24-bit number
101
102 task->SetCurrentWeight(NO_WEIGHT);
103
104 AddActive(task);
105 }
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:215
void AddActive(IKernelTask *task)
Append task to m_tasks and update the total weight.

References AddActive(), stk::IKernelTask::GetWeight(), stk::NO_WEIGHT, stk::IKernelTask::SetCurrentWeight(), and STK_ASSERT.

Here is the call graph for this function:

◆ GetFirst()

IKernelTask * stk::SwitchStrategySmoothWeightedRoundRobin::GetFirst ( )
inlineoverridevirtual

Get first task in the managed set (used by the kernel for initial scheduling).

Returns
The first task in m_tasks if any task is runnable, otherwise the first task in m_sleep. Asserts if the combined set is empty (GetSize() == 0).
Note
Preference is given to runnable tasks. The sleep fallback allows the kernel to identify any task even when all are currently sleeping.

Implements stk::ITaskSwitchStrategy.

Definition at line 180 of file stk_strategy_swrrobin.h.

181 {
182 STK_ASSERT(GetSize() != 0U);
183
184 return (*(!m_tasks.IsEmpty() ? m_tasks.GetFirst() : m_sleep.GetFirst()));
185 }
size_t GetSize() const override
Get the total number of tasks managed by this strategy.

References GetSize(), m_sleep, m_tasks, and STK_ASSERT.

Here is the call graph for this function:

◆ GetNext()

IKernelTask * stk::SwitchStrategySmoothWeightedRoundRobin::GetNext ( )
inlineoverridevirtual

Select and return the next task to run, applying one step of the SWRR algorithm.

Returns
The task with the highest current weight after the update step, or NULL if m_tasks is empty (no runnable tasks - kernel will sleep).
Note
Algorithm applied per call (O(n) over runnable tasks):
  1. For every task in m_tasks: current_weight += static_weight.
  2. Scan for the task with the maximum current_weight (initial sentinel: INT32_MIN - never equals a valid weight).
  3. Deduct the total runnable weight from the winner: selected->current_weight -= m_total_weight.
The assertion selected != NULL guards against a logic error where m_tasks is non-empty but no task was picked (should never occur).

Implements stk::ITaskSwitchStrategy.

Definition at line 142 of file stk_strategy_swrrobin.h.

143 {
144 IKernelTask *next = nullptr;
145
146 if (!m_tasks.IsEmpty())
147 {
148 IKernelTask *itr = (*m_tasks.GetFirst()), *const start = itr;
149 int32_t max_weight = INT32_MIN;
150
151 do
152 {
153 const int32_t candidate_weight = itr->GetCurrentWeight() + itr->GetWeight();
154 itr->SetCurrentWeight(candidate_weight);
155
156 if (candidate_weight > max_weight)
157 {
158 max_weight = candidate_weight;
159 next = itr;
160 }
161
162 itr = (*itr->GetNext());
163 }
164 while (itr != start);
165
166 STK_ASSERT(next != nullptr);
167
168 next->SetCurrentWeight(max_weight - m_total_weight);
169 }
170
171 return next;
172 }

References stk::IKernelTask::GetCurrentWeight(), stk::util::DListEntry< T, TClosedLoop >::GetNext(), stk::IKernelTask::GetWeight(), m_tasks, m_total_weight, stk::IKernelTask::SetCurrentWeight(), and STK_ASSERT.

Here is the call graph for this function:

◆ GetSize()

size_t stk::SwitchStrategySmoothWeightedRoundRobin::GetSize ( ) const
inlineoverridevirtual

Get the total number of tasks managed by this strategy.

Returns
Sum of tasks in m_tasks (runnable) and m_sleep (sleeping).

Implements stk::ITaskSwitchStrategy.

Definition at line 190 of file stk_strategy_swrrobin.h.

191 {
192 return m_tasks.GetSize() + m_sleep.GetSize();
193 }

References m_sleep, and m_tasks.

Referenced by GetFirst().

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 1167 of file stk_common.h.

1168 {
1169 STK_UNUSED(task);
1170 return false;
1171 }
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608

References STK_UNUSED.

◆ OnTaskSleep()

void stk::SwitchStrategySmoothWeightedRoundRobin::OnTaskSleep ( IKernelTask * task)
inlineoverridevirtual

Notification that a task has entered the sleeping state.

Parameters
[in]taskThe task that is now sleeping. Must be in m_tasks (asserted).
Note
Moves the task from m_tasks to m_sleep via RemoveActive(), which also decrements m_total_weight by the task's static weight. Sleeping tasks do not participate in weight distribution until they wake.

Implements stk::ITaskSwitchStrategy.

Definition at line 201 of file stk_strategy_swrrobin.h.

202 {
203 STK_ASSERT(task != nullptr);
204 STK_ASSERT(task->IsSleeping());
205 STK_ASSERT(task->GetHead() == &m_tasks);
206
207 RemoveActive(task);
208 m_sleep.LinkBack(task);
209 }
void RemoveActive(IKernelTask *task)
Remove task from m_tasks and update the total weight.

References stk::util::DListEntry< T, TClosedLoop >::GetHead(), stk::IKernelTask::IsSleeping(), m_sleep, m_tasks, RemoveActive(), and STK_ASSERT.

Here is the call graph for this function:

◆ OnTaskWake()

void stk::SwitchStrategySmoothWeightedRoundRobin::OnTaskWake ( IKernelTask * task)
inlineoverridevirtual

Notification that a task has become runnable again.

Parameters
[in]taskThe task that woke up. Must be in m_sleep (asserted).
Note
Applies a priority boost before re-inserting into m_tasks: the task's current weight is set to m_total_weight (the sum of all runnable tasks' static weights). On the next GetNext() call every runnable task increases its current weight by its static weight, but the waking task starts from m_total_weight, giving it the highest initial value and guaranteeing it is selected first. This prevents starvation of tasks that had been blocking on I/O or synchronization objects, and mimics the fairness behaviour of plain Round-Robin for equal-weight tasks.
After the boost, delegates to AddActive() which increments m_total_weight.

Implements stk::ITaskSwitchStrategy.

Definition at line 223 of file stk_strategy_swrrobin.h.

224 {
225 STK_ASSERT(task != nullptr);
226 STK_ASSERT(!task->IsSleeping());
227 STK_ASSERT(task->GetHead() == &m_sleep);
228
229 m_sleep.Unlink(task);
230
231 // boost priority of the previously sleeping task, this resembles to a RR pattern
232 // with tasks having equal weights
233 task->SetCurrentWeight(m_total_weight);
234
235 AddActive(task);
236 }

References AddActive(), stk::util::DListEntry< T, TClosedLoop >::GetHead(), stk::IKernelTask::IsSleeping(), m_sleep, m_total_weight, stk::IKernelTask::SetCurrentWeight(), and STK_ASSERT.

Here is the call graph for this function:

◆ OnTaskWeightChange()

virtual void stk::ITaskSwitchStrategy::OnTaskWeightChange ( IKernelTask * task,
Weight old_weight )
inlinevirtualinherited

Notification that a runnable task's scheduling weight has changed.

Parameters
[in]taskThe task whose weight was just updated via SetWeight().
[in]old_weightThe previous weight of this task (required to remove it from the priority list belonging to that weight).
Note
Called only for tasks that are currently in the runnable set (not sleeping). The strategy must relink the task to reflect its new weight. For strategies with WEIGHT_API = 0 this is a no-op. For SwitchStrategyFixedPriority it moves the task from its old priority-level list to the new one and updates m_ready_bitmap.
Called from within a ScopedCriticalSection.

Reimplemented in stk::SwitchStrategyFixedPriority< MAX_PRIORITIES >, and stk::SwitchStrategyFixedPriority< 32 >.

Definition at line 1185 of file stk_common.h.

1186 {
1187 STK_UNUSED(task);
1188 STK_UNUSED(old_weight);
1189 }

References STK_UNUSED.

◆ RemoveActive()

void stk::SwitchStrategySmoothWeightedRoundRobin::RemoveActive ( IKernelTask * task)
inlineprivate

Remove task from m_tasks and update the total weight.

Parameters
[in]taskRunnable task to remove.
Note
Decrements m_total_weight by the task's static weight so that the post-selection deduction in GetNext() and the wake-up boost in OnTaskWake() remain proportionally correct for the remaining tasks.

Definition at line 258 of file stk_strategy_swrrobin.h.

259 {
260 m_tasks.Unlink(task);
261 m_total_weight -= task->GetWeight();
262 }

References stk::IKernelTask::GetWeight(), m_tasks, and m_total_weight.

Referenced by OnTaskSleep(), and RemoveTask().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RemoveTask()

void stk::SwitchStrategySmoothWeightedRoundRobin::RemoveTask ( IKernelTask * task)
inlineoverridevirtual

Remove task from whichever list it currently occupies.

Parameters
[in]taskTask to remove. Must not be NULL and must belong to either m_tasks or m_sleep (asserted).
Note
If the task is in m_tasks, delegates to RemoveActive() which also decrements m_total_weight. If the task is in m_sleep, simply unlinks it (m_total_weight is not adjusted since sleeping tasks are already excluded from the weight sum).

Implements stk::ITaskSwitchStrategy.

Definition at line 115 of file stk_strategy_swrrobin.h.

116 {
117 STK_ASSERT(task != nullptr);
118 STK_ASSERT((task->GetHead() == &m_tasks) || (task->GetHead() == &m_sleep));
119
120 if (task->GetHead() == &m_tasks)
121 {
122 RemoveActive(task);
123 }
124 else
125 {
126 m_sleep.Unlink(task);
127 }
128 }

References stk::util::DListEntry< T, TClosedLoop >::GetHead(), m_sleep, m_tasks, RemoveActive(), and STK_ASSERT.

Here is the call graph for this function:

◆ STK_NONCOPYABLE_CLASS()

stk::SwitchStrategySmoothWeightedRoundRobin::STK_NONCOPYABLE_CLASS ( SwitchStrategySmoothWeightedRoundRobin )
private

References SwitchStrategySmoothWeightedRoundRobin().

Here is the call graph for this function:

Member Data Documentation

◆ m_sleep

IKernelTask::ListHeadType stk::SwitchStrategySmoothWeightedRoundRobin::m_sleep
private

Sleeping (blocked) tasks not eligible for scheduling.

Definition at line 265 of file stk_strategy_swrrobin.h.

Referenced by GetFirst(), GetSize(), OnTaskSleep(), OnTaskWake(), RemoveTask(), and SwitchStrategySmoothWeightedRoundRobin().

◆ m_tasks

IKernelTask::ListHeadType stk::SwitchStrategySmoothWeightedRoundRobin::m_tasks
private

Runnable tasks eligible for scheduling.

Definition at line 264 of file stk_strategy_swrrobin.h.

Referenced by AddActive(), GetFirst(), GetNext(), GetSize(), OnTaskSleep(), RemoveActive(), RemoveTask(), and SwitchStrategySmoothWeightedRoundRobin().

◆ m_total_weight

int32_t stk::SwitchStrategySmoothWeightedRoundRobin::m_total_weight
private

Sum of static weights (GetWeight()) of all tasks currently in m_tasks. Sleeping tasks are excluded. Updated on every AddActive() / RemoveActive() call. Used as the post-selection deduction amount in GetNext() and as the wake-up boost value in OnTaskWake().

Definition at line 266 of file stk_strategy_swrrobin.h.

Referenced by AddActive(), GetNext(), OnTaskWake(), RemoveActive(), and SwitchStrategySmoothWeightedRoundRobin().


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