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
stktest_switchstrategymonotonic.cpp
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#include "stktest.h"
11
12namespace stk {
13namespace test {
14
15// ============================================================================ //
16// ============================ SwitchStrategyMonotonic ====================== //
17// ============================================================================ //
18
20{
21 void setup() {}
22 void teardown()
23 {
24 g_TestContext.ExpectAssert(false);
25 g_TestContext.RethrowAssertException(true);
26 }
27};
28
30{
32
33 try
34 {
35 g_TestContext.ExpectAssert(true);
36 rr.GetFirst();
37 CHECK_TEXT(false, "expecting assertion when empty");
38 }
39 catch (TestAssertPassed &pass)
40 {
41 CHECK(true);
42 g_TestContext.ExpectAssert(false);
43 }
44}
45
46TEST(SwitchStrategyMonotonic, SleepNotSupported)
47{
50 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
51
52 kernel.Initialize();
53 kernel.AddTask(&task1);
54
55 try
56 {
57 g_TestContext.ExpectAssert(true);
58 strategy->OnTaskSleep(strategy->GetFirst());
59 CHECK_TEXT(false, "expecting assertion - OnTaskSleep not supported");
60 }
61 catch (TestAssertPassed &pass)
62 {
63 CHECK(true);
64 g_TestContext.ExpectAssert(false);
65 }
66
67 try
68 {
69 g_TestContext.ExpectAssert(true);
70 strategy->OnTaskWake(strategy->GetFirst());
71 CHECK_TEXT(false, "expecting assertion - OnTaskWake not supported");
72 }
73 catch (TestAssertPassed &pass)
74 {
75 CHECK(true);
76 g_TestContext.ExpectAssert(false);
77 }
78
79 // we need this workaround to pass 100% coverage test by blocking the exception
80 g_TestContext.ExpectAssert(true);
81 g_TestContext.RethrowAssertException(false);
82 strategy->OnTaskSleep(strategy->GetFirst());
83 strategy->OnTaskWake(strategy->GetFirst());
84}
85
86TEST(SwitchStrategyMonotonic, OnTaskDeadlineMissedNotSupported)
87{
90 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
91
92 kernel.Initialize();
93 kernel.AddTask(&task1);
94
95 try
96 {
97 g_TestContext.ExpectAssert(true);
98 strategy->OnTaskDeadlineMissed(strategy->GetFirst());
99 CHECK_TEXT(false, "expecting assertion - OnTaskDeadlineMissed not supported");
100 }
101 catch (TestAssertPassed &pass)
102 {
103 CHECK(true);
104 g_TestContext.ExpectAssert(false);
105 }
106
107 // we need this workaround to pass 100% coverage test by blocking the exception
108 g_TestContext.ExpectAssert(true);
109 g_TestContext.RethrowAssertException(false);
110 strategy->OnTaskDeadlineMissed(strategy->GetFirst());
111}
112
114{
117 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
118
119 kernel.Initialize();
120
121 kernel.AddTask(&task1);
122 kernel.RemoveTask(&task1);
123 CHECK_EQUAL(0, strategy->GetSize());
124
125 try
126 {
127 g_TestContext.ExpectAssert(true);
128 strategy->GetNext();
129 CHECK_TEXT(false, "expecting assertion when empty");
130 }
131 catch (TestAssertPassed &pass)
132 {
133 CHECK(true);
134 g_TestContext.ExpectAssert(false);
135 }
136}
137
138template <class _SwitchStrategy>
139static void TestPriorityNext()
140{
142 TaskMock<ACCESS_USER> task1, task2, task3;
143 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
144
145 kernel.Initialize();
146
147 kernel.AddTask(&task1, 300, 300, 0);
148 kernel.AddTask(&task3, 100, 100, 0);
149 kernel.AddTask(&task2, 200, 200, 0);
150
151 // Highest priority task must be selected first
152 IKernelTask *next = strategy->GetFirst();
153 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "task3 must be selected as highest priority");
154
155 // GetNext must always return highest-priority READY task
156 next = strategy->GetNext();
157 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Highest priority task must repeat (no round-robin)");
158
159 // Remove highest priority
160 kernel.RemoveTask(&task3);
161
162 next = strategy->GetNext();
163 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "task2 becomes highest priority after task3 removal");
164
165 // Remove next highest
166 kernel.RemoveTask(&task2);
167
168 next = strategy->GetNext();
169 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "task1 remains as only task");
170}
171
176
181
182template <class _SwitchStrategy>
183static void TestAlgorithm()
184{
186 TaskMock<ACCESS_USER> task1, task2, task3;
187 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
188
189 kernel.Initialize();
190
191 // --- Stage 1: Add first task -----------------------------------------
192
193 kernel.AddTask(&task1, 300, 300, 0);
194
195 IKernelTask *next = strategy->GetFirst();
196
197 // Single task -> always returned
198 for (int32_t i = 0; i < 5; i++)
199 {
200 next = strategy->GetNext();
201 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Single task must always be selected");
202 }
203
204 // --- Stage 2: Add second task ----------------------------------------
205
206 kernel.AddTask(&task2, 200, 200, 0); // higher priority than task1
207
208 next = strategy->GetNext();
209 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "Higher priority task2 should preempt task1");
210
211 next = strategy->GetNext();
212 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "Highest priority task always runs");
213
214 // --- Stage 3: Add third task -----------------------------------------
215
216 kernel.AddTask(&task3, 100, 100, 0); // highest priority
217
218 next = strategy->GetNext();
219 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Highest priority task3 should run first");
220
221 next = strategy->GetNext();
222 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Highest priority task always runs");
223
224 // --- Stage 4: Remove a task ------------------------------------------
225
226 kernel.RemoveTask(&task3);
227
228 next = strategy->GetNext();
229 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "task2 becomes highest priority after task3 removal");
230
231 next = strategy->GetNext();
232 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "task2 remains highest priority");
233
234 kernel.RemoveTask(&task2);
235
236 next = strategy->GetNext();
237 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "task1 remains as only task");
238}
239
244
249
251{
253 TaskMock<ACCESS_USER> task1, task2;
254 const SwitchStrategyRM *strategy = static_cast<const SwitchStrategyRM *>(kernel.GetSwitchStrategy());
255
256 kernel.Initialize();
257
258 // Overload CPU: C/T > RMUB
259 kernel.AddTask(&task1, 50, 50, 0); // 100% CPU
260 kernel.AddTask(&task2, 60, 30, 0); // additional load
261
262 auto result = SchedulabilityCheck::IsSchedulableWCRT<2>(strategy);
263
264 CHECK_EQUAL(100, result.info[0].cpu_load.total);
265 CHECK_EQUAL(150, result.info[1].cpu_load.total);
266
267 CHECK_FALSE_TEXT(result, "Task set should be unschedulable according to WCRT");
268}
269
271{
273 TaskMock<ACCESS_USER> task1, task2, task3, task4;
274 const SwitchStrategyRM *strategy = static_cast<const SwitchStrategyRM *>(kernel.GetSwitchStrategy());
275
276 kernel.Initialize();
277
278 // --- Stage 1: Schedulable tasks ---------------------------------------
279
280 // Task parameters: T = task period, C = execution time
281 kernel.AddTask(&task1, 40, 20, 0); // task1: C=20, T=40
282 kernel.AddTask(&task2, 100, 30, 0); // task2: C=30, T=100
283 kernel.AddTask(&task3, 200, 10, 0); // task3: C=10, T=200
284
285 auto result = SchedulabilityCheck::IsSchedulableWCRT<3>(strategy);
286 CHECK_TEXT(result, "Task set should be schedulable according to WCRT");
287
288 CHECK_EQUAL(50, result.info[0].cpu_load.total);
289 CHECK_EQUAL(80, result.info[1].cpu_load.total);
290 CHECK_EQUAL(85, result.info[2].cpu_load.total);
291}
292
293} // namespace stk
294} // namespace test
Namespace of STK package.
SwitchStrategyMonotonic< MSS_TYPE_RATE > SwitchStrategyRM
Shorthand alias for SwitchStrategyMonotonic<MSS_TYPE_RATE>: Rate-Monotonic scheduling (shorter schedu...
Namespace of the test inventory.
TestContext g_TestContext
Global instance of the TestContext.
Definition stktest.cpp:16
TEST_GROUP(Kernel)
TEST(Kernel, MaxTasks)
Concrete implementation of IKernel.
Definition stk.h:83
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT)
Prepare kernel for use: reset state, configure the platform, and register the service singleton.
Definition stk.h:805
ITaskSwitchStrategy * GetSwitchStrategy()
Get task-switching strategy instance owned by this kernel.
Definition stk.h:959
void RemoveTask(ITask *user_task)
Remove a previously added task from the kernel before Start().
Definition stk.h:895
void AddTask(ITask *user_task)
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:832
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:493
virtual ITask * GetUserTask()=0
Get user task.
Interface for a task switching strategy implementation.
Definition stk_common.h:782
virtual void OnTaskSleep(IKernelTask *task)=0
Notification that a task has entered sleep/blocked state.
virtual void OnTaskWake(IKernelTask *task)=0
Notification that a task is becoming runnable again.
virtual size_t GetSize() const =0
Get number of tasks currently managed by this strategy.
virtual IKernelTask * GetNext()=0
Advance the internal iterator and return the next runnable task.
virtual IKernelTask * GetFirst() const =0
Get first task.
virtual bool OnTaskDeadlineMissed(IKernelTask *task)=0
Notification that a task has exceeded its HRT deadline; returns whether the strategy can recover with...
Monotonic scheduling strategy: Rate-Monotonic (RM) or Deadline-Monotonic (DM), selected at compile ti...
IKernelTask * GetFirst() const
Get the first task in the managed set (used by the kernel for initial scheduling).
static SchedulabilityCheckResult< _TaskCount > IsSchedulableWCRT(const ITaskSwitchStrategy *strategy)
Perform WCRT schedulability analysis on the task set registered with strategy.
Throwable class for catching assertions from STK_ASSERT_HANDLER().
Definition stktest.h:67