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_switchstrategyfpriority.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// ========================== SwitchStrategyFixedPriority ===================== //
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
47{
50 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
51
52 kernel.Initialize();
53
54 kernel.AddTask(&task1);
55 kernel.RemoveTask(&task1);
56 CHECK_EQUAL(0, strategy->GetSize());
57
58 // expect to return NULL which puts core into a sleep mode, current is ignored by this strategy
59 CHECK_EQUAL(0, strategy->GetNext());
60}
61
62TEST(SwitchStrategyFixedPriority, OnTaskDeadlineMissedNotSupported)
63{
66 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
67
68 kernel.Initialize();
69 kernel.AddTask(&task1);
70
71 try
72 {
73 g_TestContext.ExpectAssert(true);
74 strategy->OnTaskDeadlineMissed(strategy->GetFirst());
75 CHECK_TEXT(false, "expecting assertion - OnTaskDeadlineMissed not supported");
76 }
77 catch (TestAssertPassed &pass)
78 {
79 CHECK(true);
80 g_TestContext.ExpectAssert(false);
81 }
82
83 // we need this workaround to pass 100% coverage test by blocking the exception
84 g_TestContext.ExpectAssert(true);
85 g_TestContext.RethrowAssertException(false);
86 strategy->OnTaskDeadlineMissed(strategy->GetFirst());
87}
88
90{
92 TaskMock<ACCESS_USER> task1, task2, task3;
93 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
94
95 kernel.Initialize();
96 kernel.AddTask(&task1);
97 kernel.AddTask(&task2);
98 kernel.AddTask(&task3);
99
100 IKernelTask *first = strategy->GetFirst();
101 CHECK_EQUAL_TEXT(&task1, first->GetUserTask(), "expecting first task1");
102
103 IKernelTask *next = strategy->GetNext();
104 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "expecting next task1");
105
106 next = strategy->GetNext();
107 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "expecting next task2");
108
109 next = strategy->GetNext();
110 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "expecting next task3");
111
112 next = strategy->GetNext();
113 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "expecting next task1 again (endless looping)");
114
115 next = strategy->GetNext();
116 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "expecting next task2 again (endless looping)");
117
118 kernel.RemoveTask(&task2);
119
120 next = strategy->GetNext();
121 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "expecting next task3 again (endless looping)");
122
123 next = strategy->GetNext();
124 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "expecting next task1 again (endless looping)");
125}
126
128{
129 // Create kernel with 3 tasks
131 TaskMock<ACCESS_USER> task1, task2, task3;
132
133 kernel.Initialize();
134
135 // Add tasks
136 kernel.AddTask(&task1);
137
138 ITaskSwitchStrategy *strategy = kernel.GetSwitchStrategy();
139
140 IKernelTask *next = strategy->GetFirst();
141
142 // --- Stage 1: 1 task only ---------------------------------------------
143
144 // Always returns the same task
145 for (int32_t i = 0; i < 5; i++)
146 {
147 next = strategy->GetNext();
148 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Single task must always be selected");
149 }
150
151 // --- Stage 2: add second task -----------------------------------------
152
153 kernel.AddTask(&task2);
154
155 next = strategy->GetNext(); // should still return task1 as task2 will be scheduled after this call
156 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Next task should be task1");
157 next = strategy->GetNext(); // should return task2
158 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "Next task should be task2");
159 next = strategy->GetNext(); // should wrap around to task1
160 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Next task should wrap to task1");
161
162 // --- Stage 3: add third task ------------------------------------------
163
164 kernel.AddTask(&task3);
165
166 // Expected sequence: task1 -> task2 -> task3 -> task1 ...
167 next = strategy->GetNext(); // task2
168 CHECK_EQUAL_TEXT(&task2, next->GetUserTask(), "Next task should be task2");
169 next = strategy->GetNext(); // task3
170 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Next task should be task3");
171 next = strategy->GetNext(); // task1
172 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Next task should wrap to task1");
173
174 // --- Stage 4: remove a task -------------------------------------------
175
176 kernel.RemoveTask(&task2);
177
178 // Expected sequence: task1 -> task3 -> task1 -> task3 ...
179 next = strategy->GetNext(); // task3
180 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Next task should be task3 after removal");
181 next = strategy->GetNext(); // task1
182 CHECK_EQUAL_TEXT(&task1, next->GetUserTask(), "Next task should be task1 after removal");
183 next = strategy->GetNext(); // task3
184 CHECK_EQUAL_TEXT(&task3, next->GetUserTask(), "Next task should wrap to task3");
185}
186
188{
193
194 void Clear()
195 {
196 counter = 0;
197 platform = NULL;
198 task1 = NULL;
199 task2 = NULL;
200 }
201
202 uint32_t counter;
205
206 void Process()
207 {
208 Stack *&active = platform->m_stack_active;
209
210 platform->ProcessTick();
211
212 // ISR calls OnSysTick (task1 = active, task2 = idle (sleeping))
213 if (counter == 0)
214 {
215 CHECK_EQUAL_TEXT(active->SP, (size_t)task1->GetStack(), "sleep: expecting low-priority task1");
216 }
217 else
218 // ISR calls OnSysTick (task1 = idle (lower priority), task2 = active (higher priority))
219 if (counter == 1)
220 {
221 CHECK_EQUAL_TEXT(active->SP, (size_t)task2->GetStack(), "sleep: expecting high-priority task2");
222 }
223
224 ++counter;
225 }
226}
228
230{
232}
233
235{
237 TaskMockW<1, ACCESS_USER> task1; // low priority
238 TaskMockW<2, ACCESS_USER> task2; // high priority
239 PlatformTestMock *platform = static_cast<PlatformTestMock *>(kernel.GetPlatform());
240 Stack *&active = platform->m_stack_active;
241
242 kernel.Initialize();
243 kernel.AddTask(&task1);
244 kernel.AddTask(&task2);
245 kernel.Start();
246
247 CHECK_EQUAL_TEXT(active->SP, (size_t)task2.GetStack(), "expecting high-priority task2 on start");
248
249 platform->ProcessTick();
250 CHECK_EQUAL_TEXT(active->SP, (size_t)task2.GetStack(), "expecting task2");
251
254 g_PrioritySleepRelaxCpuContext.platform = platform;
255 g_PrioritySleepRelaxCpuContext.task1 = &task1;
256 g_PrioritySleepRelaxCpuContext.task2 = &task2;
257
258 // task2 calls Sleep to become idle
259 Sleep(2);
260
261 // task2 is active again
262 CHECK_EQUAL_TEXT(active->SP, (size_t)task2.GetStack(), "expecting high-priority task2 again after it slept");
263
264 // ISR calls OnSysTick, higher priority task2 is scheduled
265 platform->ProcessTick();
266 CHECK_EQUAL_TEXT(active->SP, (size_t)task2.GetStack(), "expecting high-priority task2 again");
267
268 g_RelaxCpuHandler = NULL;
269}
270
271} // namespace stk
272} // namespace test
void(* g_RelaxCpuHandler)()
__stk_relax_cpu handler.
Definition stktest.cpp:17
Namespace of STK package.
void Sleep(uint32_t ticks)
Put calling process into a sleep state.
Definition stk_helper.h:298
SwitchStrategyFixedPriority< 32 > SwitchStrategyFP32
Shorthand alias for SwitchStrategyFixedPriority<32>: 32 priority levels (0..31), using a single 32-bi...
Namespace of the test inventory.
static struct stk::test::PrioritySleepRelaxCpuContext g_PrioritySleepRelaxCpuContext
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 Start()
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:921
void RemoveTask(ITask *user_task)
Remove a previously added task from the kernel before Start().
Definition stk.h:895
IPlatform * GetPlatform()
Get platform driver instance owned by this kernel.
Definition stk.h:954
void AddTask(ITask *user_task)
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:832
Stack descriptor.
Definition stk_common.h:181
Word SP
Stack Pointer (SP) register (note: must be the first entry in this struct).
Definition stk_common.h:182
Interface for a user task.
Definition stk_common.h:433
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 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...
Fixed-priority preemptive scheduling strategy with round-robin arbitration within each priority level...
IKernelTask * GetFirst() const
Get the first task in the managed set (used by the kernel for initial scheduling).
Throwable class for catching assertions from STK_ASSERT_HANDLER().
Definition stktest.h:67
IPlatform mock.
Definition stktest.h:75
void ProcessTick()
Process one tick.
Definition stktest.h:180
Task mock for SwitchStrategySmoothWeightedRoundRobin and similar algorithms.
Definition stktest.h:357