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_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 TStrategyType>
70{
71public:
82
86 {}
87
92
109 void AddTask(IKernelTask *task) override
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 = false;
125 switch (TStrategyType)
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 itr = (*itr->GetNext());
152 if (itr == start)
153 {
154 m_tasks.LinkBack(task);
155 break;
156 }
157 }
158 }
159 }
160
167 void RemoveTask(IKernelTask *task) override
168 {
169 STK_ASSERT(task != nullptr);
170 STK_ASSERT(GetSize() != 0U);
171 STK_ASSERT(task->GetHead() == &m_tasks);
172
173 m_tasks.Unlink(task);
174 }
175
186 {
187 IKernelTask *next = nullptr;
188
189 if (!m_tasks.IsEmpty())
190 {
191 IKernelTask *itr = (*m_tasks.GetFirst()), *const start = itr;
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 itr = (*itr->GetNext());
204 }
205 while (itr != start);
206 }
207
208 // nullptr means all tasks are sleeping, return idle signal to kernel
209 return next;
210 }
211
221 {
222 STK_ASSERT(m_tasks.GetSize() != 0U);
223
224 return (*m_tasks.GetFirst());
225 }
226
231 size_t GetSize() const override
232 {
233 return m_tasks.GetSize();
234 }
235
241 void OnTaskSleep(IKernelTask */*task*/) override
242 {
243 // Sleep API unsupported: RM/DM keeps a single sorted non-volatile list.
244 STK_ASSERT(false);
245 }
246
250 void OnTaskWake(IKernelTask */*task*/) override
251 {
252 // Sleep API unsupported: RM/DM keeps a single sorted non-volatile list.
253 STK_ASSERT(false);
254 }
255
256private:
258
260};
261
275{
276public:
291 {
292 uint32_t duration;
293 uint32_t period;
294 };
295
300 {
301 uint16_t task;
302 uint16_t total;
303 };
304
308 struct TaskInfo
309 {
311 uint32_t wcrt;
312 };
313
329 template <uint32_t TTaskCount>
331 {
333 TaskInfo info[TTaskCount];
334
338 operator bool() const { return schedulable; }
339 };
340
353 template <uint32_t TTaskCount>
355 {
356 STK_ASSERT(strategy != nullptr);
357 STK_ASSERT(const_cast<ITaskSwitchStrategy *>(strategy)->GetFirst() != nullptr);
358
359 const IKernelTask::ListHeadType *const ktasks = const_cast<ITaskSwitchStrategy *>(strategy)->GetFirst()->GetHead();
360
361 STK_ASSERT(ktasks != nullptr);
362 STK_ASSERT(ktasks->GetSize() <= TTaskCount);
363
365 TaskTiming tasks[TTaskCount];
366
367 // fill tasks timing
368 const IKernelTask *itr = (*ktasks->GetFirst()), * const start = itr;
369 uint32_t idx = 0U;
370 do
371 {
372 STK_ASSERT(idx < TTaskCount);
373
374 tasks[idx].period = static_cast<uint32_t>(itr->GetHrtPeriodicity());
375 tasks[idx].duration = static_cast<uint32_t>(itr->GetHrtDeadline());
376 ++idx;
377
378 itr = (*itr->GetNext());
379 }
380 while (itr != start);
381
382 STK_ASSERT(idx == TTaskCount);
383
384 // calculate CPU load
385 GetTaskCpuLoad(tasks, TTaskCount, ret.info);
386
387 // run the WCRT schedulability analysis
388 ret.schedulable = CalculateWCRT(tasks, TTaskCount, ret.info);
389
390 return ret;
391 }
392
425 static inline bool CalculateWCRT(const TaskTiming tasks[], const uint32_t count, TaskInfo info[])
426 {
427 bool schedulable = true;
428 info[0].wcrt = tasks[0].duration;
429
430 for (uint32_t t = 1U; t < count; )
431 {
432 uint32_t w;
433 const uint32_t Cx = tasks[t].duration;
434 const uint32_t Tx = tasks[t].period;
435 uint32_t w0 = Cx;
436
437 next_itr:
438
439 w = Cx;
440 for (uint32_t i = 0U; i < t; ++i)
441 {
442 w += idiv_ceil(w0, tasks[i].period) * tasks[i].duration;
443 }
444
445 if ((w != w0) && (w <= Tx))
446 {
447 w0 = w;
448 goto next_itr;
449 }
450 else
451 {
452 schedulable &= (w <= Tx);
453 info[t++].wcrt = w;
454 }
455 }
456
457 return schedulable;
458 }
459
468 static inline void GetTaskCpuLoad(const TaskTiming tasks[], const uint32_t count, TaskInfo info[])
469 {
470 uint16_t total = 0U;
471
472 for (uint32_t i = 0U; i < count; ++i)
473 {
474 const uint16_t task_load = static_cast<uint16_t>(tasks[i].duration * 100U / tasks[i].period);
475 total += task_load;
476
477 info[i].cpu_load.task = task_load;
478 info[i].cpu_load.total = total;
479 }
480 }
481
482private:
488 static inline uint32_t idiv_ceil(uint32_t x, uint32_t y)
489 {
490 uint32_t result = 0U;
491
492 if (y != 0U)
493 {
494 result = x / y;
495
496 if ((x % y) > 0U)
497 {
498 result++;
499 }
500 }
501
502 return result;
503 }
504};
505
512
519
520} // namespace stk
521
522#endif /* STK_STRATEGY_RM_H_ */
Contains interface definitions of the library.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
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:748
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:753
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.
size_t GetSize() const
Get the number of entries currently in the list.
DLEntryType * GetFirst()
Get the first (front) entry without removing it.
DLEntryType * GetNext()
Get the next entry in the list.
DLHeadType * GetHead()
Get the list head this entry currently belongs to.
DLEntryType * GetPrev()
Get the previous 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.
void RemoveTask(IKernelTask *task) override
Remove a task from the list.
SwitchStrategyMonotonic()
Construct an empty strategy with no tasks.
void OnTaskWake(IKernelTask *) override
Not supported, asserts unconditionally.
void OnTaskSleep(IKernelTask *) override
Not supported, asserts unconditionally.
STK_NONCOPYABLE_CLASS(SwitchStrategyMonotonic)
STK_VIRT_DTOR ~SwitchStrategyMonotonic()=default
Destructor.
size_t GetSize() const override
Get the total number of tasks managed by this strategy.
IKernelTask * GetNext() override
Select and return the highest-priority non-sleeping task.
void AddTask(IKernelTask *task) override
Add a task to the priority-sorted runnable list.
IKernelTask * GetFirst() override
Get the first task in the managed set (used by the kernel for initial scheduling).
Utility class providing static methods for Worst-Case Response Time (WCRT) schedulability analysis of...
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 void GetTaskCpuLoad(const TaskTiming tasks[], const uint32_t count, TaskInfo info[])
Compute per-task and cumulative CPU utilization, in whole percent.
static SchedulabilityCheckResult< TTaskCount > IsSchedulableWCRT(const ITaskSwitchStrategy *strategy)
Perform WCRT schedulability analysis on the task set registered with strategy.
static uint32_t idiv_ceil(uint32_t x, uint32_t y)
Compute the ceiling of an integer division: ceil(x / 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[TTaskCount]
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.