SuperTinyKernel™ RTOS 1.05.3
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_strategy_monotonic.h
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#ifndef STK_STRATEGY_RM_H_
11#define STK_STRATEGY_RM_H_
12
18
19#include "stk_common.h"
20#include "stk_strategy_rrobin.h"
21
22namespace stk {
23
33
68template <EMonotonicSwitchStrategyType _Type>
70{
71public:
81
85 {}
86
92
110 {
111 STK_ASSERT(task != nullptr);
112 STK_ASSERT(task->GetHead() == nullptr);
113
114 if (m_tasks.IsEmpty())
115 {
116 m_tasks.LinkFront(task);
117 }
118 else
119 {
120 IKernelTask *itr = (*m_tasks.GetFirst()), * const start = itr;
121
122 for (;;)
123 {
124 bool higher_priority;
125 switch (_Type)
126 {
127 case MSS_TYPE_RATE:
128 higher_priority = (task->GetHrtPeriodicity() < itr->GetHrtPeriodicity());
129 break;
131 higher_priority = (task->GetHrtDeadline() < itr->GetHrtDeadline());
132 break;
133 default:
134 STK_ASSERT(false);
135 break;
136 }
137
138 if (higher_priority)
139 {
140 if (itr == start)
141 {
142 m_tasks.LinkFront(task);
143 break;
144 }
145
146 m_tasks.Link(task, itr, itr->GetPrev());
147 break;
148 }
149
150 // end of the list
151 if ((itr = (*itr->GetNext())) == start)
152 {
153 m_tasks.LinkBack(task);
154 break;
155 }
156 }
157 }
158 }
159
167 {
168 STK_ASSERT(task != nullptr);
169 STK_ASSERT(GetSize() != 0U);
170 STK_ASSERT(task->GetHead() == &m_tasks);
171
172 m_tasks.Unlink(task);
173 }
174
187 {
188 STK_ASSERT(!m_tasks.IsEmpty());
189
190 IKernelTask *itr = (*m_tasks.GetFirst()), * const start = itr;
191 IKernelTask *next = nullptr;
192
193 // Scan from head (highest priority). Skip tasks that are sleeping between
194 // periodic activations; return the first task ready to run.
195 do
196 {
197 if (!itr->IsSleeping())
198 {
199 next = itr;
200 break; // list is sorted by priority; no need to continue
201 }
202 }
203 while ((itr = (*itr->GetNext())) != start);
204
205 // nullptr means all tasks are sleeping, return idle signal to kernel
206 return next;
207 }
208
218 {
219 STK_ASSERT(m_tasks.GetSize() != 0U);
220
221 return (*m_tasks.GetFirst());
222 }
223
228 size_t GetSize() const
229 {
230 return m_tasks.GetSize();
231 }
232
238 void OnTaskSleep(IKernelTask */*task*/)
239 {
240 // Sleep API unsupported: RM/DM keeps a single sorted non-volatile list.
241 STK_ASSERT(false);
242 }
243
247 void OnTaskWake(IKernelTask */*task*/)
248 {
249 // Sleep API unsupported: RM/DM keeps a single sorted non-volatile list.
250 STK_ASSERT(false);
251 }
252
257 {
258 // Budget Overrun API unsupported
259 STK_ASSERT(false);
260 return false;
261 }
262
263private:
265
267};
268
282{
283public:
298 {
299 uint32_t duration;
300 uint32_t period;
301 };
302
307 {
308 uint16_t task;
309 uint16_t total;
310 };
311
315 struct TaskInfo
316 {
318 uint32_t wcrt;
319 };
320
336 template <uint32_t _TaskCount>
338 {
340 TaskInfo info[_TaskCount];
341
345 operator bool() const { return schedulable; }
346 };
347
360 template <uint32_t _TaskCount>
362 {
363 STK_ASSERT(strategy != nullptr);
364 STK_ASSERT(strategy->GetFirst() != nullptr);
365
366 const IKernelTask::ListHeadType *ktasks = strategy->GetFirst()->GetHead();
367
368 STK_ASSERT(ktasks != nullptr);
369 STK_ASSERT(ktasks->GetSize() <= _TaskCount);
370
372 TaskTiming tasks[_TaskCount];
373
374 // fill tasks timing
375 IKernelTask *itr = (*ktasks->GetFirst()), * const start = itr;
376 uint32_t idx = 0U;
377 do
378 {
379 STK_ASSERT(idx < _TaskCount);
380 tasks[idx].period = static_cast<uint32_t>(itr->GetHrtPeriodicity());
381 tasks[idx].duration = static_cast<uint32_t>(itr->GetHrtDeadline());
382 idx += 1U;
383 }
384 while ((itr = (*itr->GetNext())) != start);
385 STK_ASSERT(idx == _TaskCount);
386
387 // calculate CPU load
388 GetTaskCpuLoad(tasks, _TaskCount, ret.info);
389
390 // run the WCRT schedulability analysis
391 ret.schedulable = CalculateWCRT(tasks, _TaskCount, ret.info);
392
393 return ret;
394 }
395
428 static inline bool CalculateWCRT(const TaskTiming *tasks, const uint32_t count, TaskInfo *info)
429 {
430 bool schedulable = true;
431 info[0].wcrt = tasks[0].duration;
432
433 for (uint32_t t = 1; t < count; )
434 {
435 uint32_t w,
436 Cx = tasks[t].duration,
437 Tx = tasks[t].period,
438 w0 = Cx;
439
440 next_itr:
441
442 w = Cx;
443 for (uint32_t i = 0; i < t; ++i)
444 w += idiv_ceil(w0, tasks[i].period) * tasks[i].duration;
445
446 if ((w != w0) && (w <= Tx))
447 {
448 w0 = w;
449 goto next_itr;
450 }
451 else
452 {
453 schedulable &= (w <= Tx);
454 info[t++].wcrt = w;
455 }
456 }
457
458 return schedulable;
459 }
460
469 static inline void GetTaskCpuLoad(const TaskTiming *tasks, const uint32_t count, TaskInfo *info)
470 {
471 uint16_t total = 0;
472
473 for (uint32_t t = 0; t < count; ++t)
474 {
475 uint16_t task_load = (uint16_t)(tasks[t].duration * 100 / tasks[t].period);
476 total += task_load;
477
478 info[t].cpu_load.task = task_load;
479 info[t].cpu_load.total = total;
480 }
481 }
482
483private:
487 static __stk_forceinline int32_t idiv_ceil(uint32_t x, uint32_t y)
488 {
489 return x / y + (x % y > 0);
490 }
491};
492
499
506
507} // namespace stk
508
509#endif /* STK_STRATEGY_RM_H_ */
Contains interface definitions of the library.
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:104
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:330
Round-Robin task-switching strategy (stk::SwitchStrategyRoundRobin / stk::SwitchStrategyRR).
Namespace of STK package.
SwitchStrategyMonotonic< MSS_TYPE_RATE > SwitchStrategyRM
Shorthand alias for SwitchStrategyMonotonic<MSS_TYPE_RATE>: Rate-Monotonic scheduling (shorter schedu...
SwitchStrategyMonotonic< MSS_TYPE_DEADLINE > SwitchStrategyDM
Shorthand alias for SwitchStrategyMonotonic<MSS_TYPE_DEADLINE>: Deadline-Monotonic scheduling (shorte...
EMonotonicSwitchStrategyType
Policy selector for SwitchStrategyMonotonic: determines the timing attribute used to assign fixed pri...
@ MSS_TYPE_DEADLINE
Deadline-Monotonic (DM): shorter execution deadline -> higher priority. Priority is derived from GetH...
@ MSS_TYPE_RATE
Rate-Monotonic (RM): shorter scheduling period -> higher priority. Priority is derived from GetHrtPer...
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:493
virtual Timeout GetHrtDeadline() const =0
Get HRT task deadline (max allowed task execution time).
DLHeadType ListHeadType
List head type for IKernelTask elements.
Definition stk_common.h:498
virtual bool IsSleeping() const =0
Check whether the task is currently sleeping.
virtual Timeout GetHrtPeriodicity() const =0
Get HRT task execution periodicity.
Interface for a task switching strategy implementation.
Definition stk_common.h:782
virtual IKernelTask * GetFirst() const =0
Get first task.
size_t GetSize() const
Get the number of entries currently in the list.
DLEntryType * GetFirst() const
Get the first (front) entry without removing it.
DLEntryType * GetPrev() const
Get the previous entry in the list.
DLHeadType * GetHead() const
Get the list head this entry currently belongs to.
DLEntryType * GetNext() const
Get the next entry in the list.
Monotonic scheduling strategy: Rate-Monotonic (RM) or Deadline-Monotonic (DM), selected at compile ti...
EConfig
Compile-time capability flags reported to the kernel.
size_t GetSize() const
Get the total number of tasks managed by this strategy.
SwitchStrategyMonotonic()
Construct an empty strategy with no tasks.
IKernelTask * GetNext()
Select and return the highest-priority non-sleeping task.
void OnTaskWake(IKernelTask *)
Not supported, asserts unconditionally.
IKernelTask * GetFirst() const
Get the first task in the managed set (used by the kernel for initial scheduling).
bool OnTaskDeadlineMissed(IKernelTask *)
Not supported, asserts unconditionally.
void RemoveTask(IKernelTask *task)
Remove a task from the list.
void OnTaskSleep(IKernelTask *)
Not supported, asserts unconditionally.
STK_NONCOPYABLE_CLASS(SwitchStrategyMonotonic)
void AddTask(IKernelTask *task)
Add a task to the priority-sorted runnable list.
Utility class providing static methods for Worst-Case Response Time (WCRT) schedulability analysis of...
static void GetTaskCpuLoad(const TaskTiming *tasks, const uint32_t count, TaskInfo *info)
Compute per-task and cumulative CPU utilization, in whole percent.
static SchedulabilityCheckResult< _TaskCount > IsSchedulableWCRT(const ITaskSwitchStrategy *strategy)
Perform WCRT schedulability analysis on the task set registered with strategy.
static bool CalculateWCRT(const TaskTiming *tasks, const uint32_t count, TaskInfo *info)
Compute the Worst-Case Response Time (WCRT) for each task in a fixed-priority periodic task set and d...
static __stk_forceinline int32_t idiv_ceil(uint32_t x, uint32_t y)
Execution deadline and scheduling period for a single periodic HRT task, used as input to CalculateWC...
uint32_t period
Scheduling period T of the task (ticks), from GetHrtPeriodicity(). Used as the interference divisor T...
uint32_t duration
Worst-Case Execution Time C of the task (ticks), from GetHrtDeadline(). Used as the base cost and int...
CPU utilisation values for a single task, in whole percent.
uint16_t task
CPU load contributed by this task alone, in percent: floor(C / T * 100) = floor(duration * 100 / peri...
uint16_t total
Cumulative CPU load of this task plus all higher-priority tasks, in percent (running sum from index 0...
Analysis results for a single task: CPU load and computed WCRT.
uint32_t wcrt
Worst-Case Response Time in ticks. Task is schedulable if wcrt <= period (T).
TaskCpuLoad cpu_load
Per-task and cumulative CPU utilisation (see TaskCpuLoad).
Result of a WCRT schedulability test: overall verdict plus per-task details.
TaskInfo info[_TaskCount]
Per-task analysis results, ordered highest priority first (index 0 = highest priority task).
bool schedulable
true if every task's WCRT <= its period (T); false if any task misses its deadline.