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.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_H_
11#define STK_H_
12
13#include "stk_helper.h"
19
34
35namespace stk {
36
79template <uint8_t TMode, uint32_t TSize, class TStrategy, class TPlatform>
80class Kernel
81#ifndef _STK_UNDER_TEST
82final
83#endif
84: public IKernel, private IPlatform::IEventHandler
85{
86protected:
92
98
103 enum ERequest : uint8_t
104 {
106 REQ_ADD_TASK = (1 << 0)
107 };
108
120 class KernelTask final : public IKernelTask
121 {
122 friend class Kernel;
123
128 enum EStateFlags : uint32_t
129 {
133 };
134
135 public:
144 {
146 };
147
153 m_srt(), m_hrt(), m_rt_weight()
154 {
155 // bind to wait object
157 {
158 m_wait_obj->m_task = this;
159 }
160 }
161
165 ITask *GetUserTask() override { return m_user; }
166
170 Stack GetUserStack() const { return m_stack;}
171
175 bool IsBusy() const { return (m_user != nullptr); }
176
180 bool IsSleeping() const override { return (m_time_sleep < 0); }
181
185 TId GetTid() const { return GetTidFromUserTask(m_user); }
186
191 void Wake() override
192 {
194
195 // wakeup on a next cycle
196 m_time_sleep = -1;
197 }
198
202 void SetCurrentWeight(Weight weight) override
203 {
204 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
205 {
206 m_rt_weight[0] = weight;
207 }
208 }
209
213 Weight GetWeight() const override
214 {
215 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
216 {
217 if (m_rt_weight[0] != NO_WEIGHT)
218 {
219 return m_rt_weight[0];
220 }
221 }
222
223 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
224 {
225 return m_user->GetWeight();
226 }
227 else
228 {
229 return DEFAULT_WEIGHT;
230 }
231 }
232
238 Weight GetCurrentWeight() const override
239 {
240 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
241 {
242 return m_rt_weight[0];
243 }
244 else
245 {
246 return DEFAULT_WEIGHT;
247 }
248 }
249
254 Timeout GetHrtPeriodicity() const override
255 {
257
259 {
260 return m_hrt[0].periodicity;
261 }
262 else
263 {
264 return 0;
265 }
266 }
267
273 Timeout GetHrtDeadline() const override
274 {
276
278 {
279 return m_hrt[0].deadline;
280 }
281 else
282 {
283 return 0;
284 }
285 }
286
293 {
296
298 {
299 return (m_hrt[0].deadline - m_hrt[0].duration);
300 }
301 else
302 {
303 return 0;
304 }
305 }
306
308 {
309 // note: task sleep time is negative
311
313 {
314 // likely task is sleeping during sync operation (see Wait)
315 if (m_wait_obj->IsWaiting())
316 {
317 // note: sync wait time is positive
318 task_sleep = m_wait_obj->m_time_wait;
319
320 // we shall account for only valid time (when task is waiting during sync operation)
321 if (task_sleep > NO_WAIT)
322 {
323 sleep_ticks = Min(sleep_ticks, task_sleep);
324 }
325 }
326 else
327 {
328 sleep_ticks = Min(sleep_ticks, task_sleep);
329 }
330 }
331 else
332 {
333 sleep_ticks = Min(sleep_ticks, task_sleep);
334 }
335
336 // clamp to [1, STK_TICKLESS_TICKS_MAX] range
337 return Max<Timeout>(1, sleep_ticks);
338 }
339
340 protected:
345
351 struct SrtInfo
352 {
354 {}
355
358 void Clear()
359 {
360 add_task_req = nullptr;
361 }
362
369 };
370
375 struct HrtInfo
376 {
377 HrtInfo() : periodicity(0), deadline(0), duration(0), done(false)
378 {}
379
382 void Clear()
383 {
384 periodicity = 0;
385 deadline = 0;
386 duration = 0;
387 done = false;
388 }
389
393 volatile bool done;
394 };
395
402 struct WaitObject final : public IWaitObject
403 {
404 explicit WaitObject() : m_task(nullptr), m_sync_obj(nullptr), m_timeout(false), m_time_wait(0)
405 {}
406
411
418 {
420 };
421
425 TId GetTid() const override { return m_task->GetTid(); }
426
430 bool IsTimeout() const override { return m_timeout; }
431
435 bool IsWaiting() const { return (m_sync_obj != nullptr); }
436
442 void Wake(bool timeout) override
443 {
445
446 m_timeout = timeout;
447 m_time_wait = 0;
448
449 m_sync_obj->RemoveWaitObject(this);
450 m_sync_obj = nullptr;
451
452 return m_task->Wake();
453 }
454
461 bool Tick(Timeout elapsed_ticks) override
462 {
464 {
465 if (!m_timeout)
466 {
467 m_time_wait -= elapsed_ticks;
468
469 if (m_time_wait <= 0)
470 {
471 m_timeout = true;
472 }
473 }
474 }
475
476 return !m_timeout;
477 }
478
486 void SetupWait(ISyncObject *sync_obj, Timeout timeout)
487 {
489
490 m_sync_obj = sync_obj;
491 m_time_wait = timeout;
492 m_timeout = false;
493
494 sync_obj->AddWaitObject(this);
495 }
496
499 volatile bool m_timeout;
501 };
502
507 void Bind(TPlatform *platform, ITask *user_task)
508 {
509 // set access mode for this stack
510 m_stack.access_mode = user_task->GetAccessMode();
511
512 // set task id for tracking purpose
513 #if STK_NEED_TASK_ID
514 m_stack.tid = user_task->GetId();
515 #endif
516
517 // init stack of the user task
518 if (!platform->InitStack(STACK_USER_TASK, &m_stack, user_task, user_task))
519 {
520 STK_ASSERT(false);
521 }
522
523 // bind user task
524 m_user = user_task;
525
526 // initialize current weight to NO_WEIGHT for priority inheritance mechanism
527 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
528 {
530 }
531 }
532
536 void Unbind()
537 {
539 {
540 // should be freed from waiting on task exit
541 STK_ASSERT(!m_wait_obj->IsWaiting());
542 }
543
544 m_user = nullptr;
545 m_stack = {};
547 m_time_sleep = 0;
548
550 {
551 m_hrt[0].Clear();
552 }
553 else
554 {
555 m_srt->Clear();
556 }
557 }
558
562 {
563 // make this task sleeping to switch it out from scheduling process
565
566 // mark it as done HRT task
568 {
570 }
571
572 // mark it as pending for removal
574 }
575
578 bool IsPendingRemoval() const { return ((m_state & STATE_REMOVE_PENDING) != 0U); }
579
583 bool IsMemoryOfSP(Word SP) const
584 {
585 const Word start = hw::PtrToWord(m_user->GetStack());
586 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
587
588 return (SP >= start) && (SP <= end);
589 }
590
597 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
598 {
599 STK_ASSERT(periodicity_tc > 0);
600 STK_ASSERT(deadline_tc > 0);
601 STK_ASSERT(start_delay_tc >= 0);
602 STK_ASSERT(periodicity_tc < INT32_MAX);
603 STK_ASSERT(deadline_tc < INT32_MAX);
604
605 m_hrt[0].periodicity = periodicity_tc;
606 m_hrt[0].deadline = deadline_tc;
607
608 if (start_delay_tc > 0)
609 {
610 ScheduleSleep(start_delay_tc);
611 }
612 }
613
618
623 void HrtOnSwitchedOut(IPlatform */*platform*/)
624 {
625 const Timeout duration = m_hrt[0].duration;
626
627 STK_ASSERT(duration >= 0);
628
629 const Timeout sleep = m_hrt[0].periodicity - duration;
630 if (sleep > 0)
631 {
632 ScheduleSleep(sleep);
633 }
634
635 m_hrt[0].duration = 0;
636 m_hrt[0].done = false;
637 }
638
644 {
645 const Timeout duration = m_hrt[0].duration;
646
647 STK_ASSERT(duration >= 0);
649
650 m_user->OnDeadlineMissed(duration);
651 platform->ProcessHardFault();
652 }
653
658 {
659 m_hrt[0].done = true;
660 __stk_full_memfence();
661 }
662
666 bool HrtIsDeadlineMissed(Timeout duration) const
667 {
668 return (duration > m_hrt[0].deadline);
669 }
670
681 {
682 STK_ASSERT(ticks > 0);
683
684 // set state first as kernel checks it when task IsSleeping
685 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
686 {
687 if (!IsSleeping())
688 {
690 }
691 }
692
693 m_time_sleep = -ticks;
694 __stk_full_memfence();
695 }
696
700 {
701 while (IsSleeping())
702 {
703 __stk_relax_cpu();
704 }
705 }
706
711
714 volatile uint32_t m_state;
720 };
721
729 class KernelService final : public IKernelService
730 {
731 friend class Kernel;
732
733 public:
734 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
735
736 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
737
738 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
739
740 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
741
742 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
743
744 void Delay(Timeout ticks) override
745 {
747 STK_ASSERT(ticks >= 0);
748
749 Ticks now = GetTicks();
750 const Ticks deadline = now + ticks;
751 STK_ASSERT(deadline >= now);
752
753 for (; now < deadline; now = GetTicks())
754 {
755 __stk_relax_cpu();
756 }
757 }
758
759 void Sleep(Timeout ticks) override
760 {
762 STK_ASSERT(ticks >= 0);
763
765 {
766 m_kernel->m_platform.Sleep(ticks);
767 }
768 else
769 {
770 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
771 STK_ASSERT(false);
772 }
773 }
774
775 bool SleepUntil(Ticks timestamp) override
776 {
778
780 {
781 return m_kernel->m_platform.SleepUntil(timestamp);
782 }
783 else
784 {
785 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
786 STK_ASSERT(false);
787 return false;
788 }
789 }
790
791 void SleepCancel(TId task_id) override
792 {
794 {
795 m_kernel->OnTaskSleepCancel(task_id);
796 }
797 }
798
799 void SwitchToNext() override
800 {
802
803 m_kernel->m_platform.SwitchToNext();
804 }
805
806 IWaitObject *Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
807 {
809 {
810 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
811 }
812 else
813 {
814 STK_ASSERT(false);
815 return nullptr;
816 }
817 }
818
819 Timeout Suspend() override
820 {
822 {
823 return m_kernel->m_platform.Suspend();
824 }
825 else
826 {
827 STK_ASSERT(false);
828 return 0;
829 }
830 }
831
832 void Resume(Timeout elapsed_ticks) override
833 {
835 {
836 return m_kernel->m_platform.Resume(elapsed_ticks);
837 }
838 else
839 {
840 STK_ASSERT(false);
841 }
842 }
843
844 void InheritWeight(TId tid, Weight weight) override
845 {
846 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
847 {
848 m_kernel->OnInheritWeight(tid, weight);
849 }
850 }
851
852 void RestoreWeight(TId tid, ISyncObject *sobj) override
853 {
854 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
855 {
856 m_kernel->OnRestoreWeight(tid, sobj);
857 }
858 }
859
860 private:
864 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
865 {}
866
871
877 void Initialize(Kernel *kernel)
878 {
879 m_kernel = kernel;
880 }
881
885 void IncrementTicks(Ticks advance)
886 {
887 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
889 }
890
892 volatile Ticks m_ticks;
893 };
894
895public:
898 static constexpr size_t TASKS_MAX = TSize;
899
909 {
910 #ifdef _DEBUG
911 // TPlatform must inherit IPlatform
912 IPlatform *platform = &m_platform;
913 STK_UNUSED(platform);
914
915 // TStrategy must inherit ITaskSwitchStrategy
916 ITaskSwitchStrategy *strategy = &m_strategy;
917 STK_UNUSED(strategy);
918 #endif
919
920 #if !STK_TICKLESS_IDLE
921 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
922 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
923 #endif
924 }
925
930
940 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
941 {
942 STK_ASSERT(resolution_us != 0);
943 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
945
946 // reinitialize key state variables
947 m_task_now = nullptr;
950
951 // exit trap is required only for KERNEL_DYNAMIC mode
952 Stack *exit_trap = nullptr;
954 {
955 exit_trap = &m_exit_trap[0].stack;
956 }
957 else
958 {
959 STK_UNUSED(exit_trap);
960 }
961
962 m_service.Initialize(this);
963 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
964
965 // now ready to Start()
967 }
968
977 __stk_attr_noinline void AddTask(ITask *user_task) override
978 {
980 {
981 STK_ASSERT(user_task != nullptr);
983
984 // when started the operation must be serialized by switching out from processing until
985 // kernel processes this request
986 if (IsStarted())
987 {
989 {
990 RequestAddTask(user_task);
991 }
992 else
993 {
994 STK_ASSERT(false);
995 }
996 }
997 else
998 {
999 AllocateAndAddNewTask(user_task);
1000 }
1001 }
1002 else
1003 {
1004 STK_ASSERT(false);
1005 }
1006 }
1007
1016 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1017 Timeout start_delay_tc) override
1018 {
1020 {
1021 STK_ASSERT(user_task != nullptr);
1024
1025 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1026 }
1027 else
1028 {
1029 STK_ASSERT(false);
1030 }
1031 }
1032
1041 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1042 {
1044 {
1045 STK_ASSERT(user_task != nullptr);
1047
1048 KernelTask *const task = FindTaskByUserTask(user_task);
1049 if (task != nullptr)
1050 {
1051 RemoveTask(task);
1052 }
1053 }
1054 else
1055 {
1056 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1057 STK_ASSERT(false);
1058 }
1059 }
1060
1067 {
1069 {
1070 STK_ASSERT(user_task != nullptr);
1072
1074
1075 KernelTask *const task = FindTaskByUserTask(user_task);
1076 if (task != nullptr)
1077 {
1078 task->ScheduleRemoval();
1079 }
1080 }
1081 else
1082 {
1083 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1084 STK_ASSERT(false);
1085 }
1086 }
1087
1094 void SuspendTask(ITask *user_task, bool &suspended) override
1095 {
1096 STK_ASSERT(user_task != nullptr);
1097
1098 bool self = false;
1099
1100 // avoid race with OnTick
1101 {
1103
1104 KernelTask *const task = FindTaskByUserTask(user_task);
1105 STK_ASSERT(task != nullptr);
1106
1107 // only suspend if the task is currently awake: if it is already sleeping
1108 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1109 // that would corrupt the original sleep state and, for sync-object waits,
1110 // would interfere with WaitObject::Tick()
1111 suspended = !task->IsSleeping();
1112 if (suspended == true)
1113 {
1114 task->ScheduleSleep(WAIT_INFINITE);
1115
1116 // check if suspending self
1117 self = (task == m_task_now);
1118 }
1119 }
1120
1121 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1122 if (self)
1123 {
1124 m_task_now->BusyWaitWhileSleeping();
1125 }
1126 }
1127
1131 void ResumeTask(ITask *user_task) override
1132 {
1133 STK_ASSERT(user_task != nullptr);
1134
1135 // avoid race with OnTick
1137
1138 KernelTask *const task = FindTaskByUserTask(user_task);
1139 STK_ASSERT(task != nullptr);
1140
1141 if (task->IsSleeping())
1142 {
1143 task->Wake();
1144 }
1145 }
1146
1152 {
1153 size_t count = 0U;
1154 const size_t limit = Min(tasks.GetSize(), static_cast<size_t>(TASKS_MAX));
1155
1156 // avoid race with OnTick
1158
1159 for (size_t i = 0U; i < limit; ++i)
1160 {
1161 KernelTask *const task = &m_task_storage[i];
1162 if (task->IsBusy())
1163 {
1164 tasks[count++] = task;
1165 }
1166 }
1167
1168 return count;
1169 }
1170
1175 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1176 {
1177 size_t count = 0U;
1178 const size_t limit = Min(user_tasks.GetSize(), static_cast<size_t>(TASKS_MAX));
1179
1180 // avoid race with OnTick
1182
1183 for (size_t i = 0U; i < limit; ++i)
1184 {
1185 KernelTask *const task = &m_task_storage[i];
1186 if (task->IsBusy())
1187 {
1188 user_tasks[count++] = task->GetUserTask();
1189 }
1190 }
1191
1192 return count;
1193 }
1194
1204 {
1206
1207 // stacks of the traps must be re-initilized on every subsequent Start
1208 InitTraps();
1209
1210 // start tracing
1211 #if STK_SEGGER_SYSVIEW
1212 SEGGER_SYSVIEW_Start();
1213 for (size_t i = 0U; i < TASKS_MAX; ++i)
1214 {
1215 KernelTask *task = &m_task_storage[i];
1216 if (task->IsBusy())
1217 {
1218 SendTaskTraceInfo(task);
1219 }
1220 }
1221 #endif
1222
1223 m_platform.Start();
1224 }
1225
1230 bool IsStarted() const
1231 {
1232 return (m_task_now != nullptr);
1233 }
1234
1238 IPlatform *GetPlatform() override { return &m_platform; }
1239
1244
1247 EKernelState GetState() const override { return m_kstate; }
1248
1249protected:
1263
1276
1283 static constexpr Timeout YIELD_TICKS = 2;
1284
1288 {
1289 return (state > FSM_STATE_NONE) &&
1290 (state < FSM_STATE_MAX);
1291 }
1292
1296 {
1297 // init stack for a Sleep trap
1298 {
1299 SleepTrapStack &sleep = m_sleep_trap[0];
1300
1301 SleepTrapStackMemory wrapper(&sleep.memory);
1302 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1303 #if STK_NEED_TASK_ID
1304 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1305 #endif
1306
1307 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1308 }
1309
1310 // init stack for an Exit trap
1312 {
1313 ExitTrapStack &exit = m_exit_trap[0];
1314
1315 ExitTrapStackMemory wrapper(&exit.memory);
1316 exit.stack.access_mode = ACCESS_PRIVILEGED;
1317 #if STK_NEED_TASK_ID
1318 exit.stack.tid = SYS_TASK_ID_EXIT;
1319 #endif
1320
1321 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1322 }
1323 }
1324
1329 KernelTask *AllocateNewTask(ITask *user_task)
1330 {
1331 // look for a free kernel task
1332 KernelTask *new_task = nullptr;
1333 for (size_t i = 0U; i < TASKS_MAX; ++i)
1334 {
1335 KernelTask *const task = &m_task_storage[i];
1336 if (task->IsBusy())
1337 {
1338 // avoid task collision
1339 STK_ASSERT(task->m_user != user_task);
1340
1341 // avoid stack collision
1342 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1343 }
1344 else
1345 if (new_task == nullptr)
1346 {
1347 new_task = task;
1348 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1349 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1350 #endif
1351 }
1352 else
1353 {
1354 // noop, continue to the next slot
1355 }
1356 }
1357
1358 // if nullptr - exceeded max supported kernel task count, application design failure
1359 STK_ASSERT(new_task != nullptr);
1360
1361 new_task->Bind(&m_platform, user_task);
1362
1363 return new_task;
1364 }
1365
1369 void AddKernelTask(KernelTask *task)
1370 {
1371 #if STK_SEGGER_SYSVIEW
1372 // start tracing new task
1373 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1374 if (IsStarted())
1375 SendTaskTraceInfo(task);
1376 #endif
1377
1378 m_strategy.AddTask(task);
1379 }
1380
1385 {
1386 KernelTask *const task = AllocateNewTask(user_task);
1387 STK_ASSERT(task != nullptr);
1388
1389 AddKernelTask(task);
1390 }
1391
1399 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1400 {
1401 KernelTask *const task = AllocateNewTask(user_task);
1402 STK_ASSERT(task != nullptr);
1403
1404 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1405
1406 AddKernelTask(task);
1407 }
1408
1414 {
1415 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1416 STK_ASSERT(caller != nullptr);
1417
1418 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1419 caller->m_srt[0].add_task_req = &req;
1420
1421 // notify kernel
1423
1424 // switch out and wait for completion (due to context switch request could be processed here)
1425 if (caller->m_srt[0].add_task_req != nullptr)
1426 {
1427 m_service.SwitchToNext();
1428 }
1429
1430 STK_ASSERT(caller->m_srt[0].add_task_req == nullptr);
1431 }
1432
1437 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
1438 {
1439 KernelTask *found_task = nullptr;
1440
1441 for (size_t i = 0U; i < TASKS_MAX; ++i)
1442 {
1443 KernelTask *const task = &m_task_storage[i];
1444 if (task->GetUserTask() == user_task)
1445 {
1446 found_task = task;
1447 break;
1448 }
1449 }
1450
1451 return found_task;
1452 }
1453
1458 KernelTask *FindTaskByStack(const Stack *stack)
1459 {
1460 KernelTask *found_task = nullptr;
1461
1462 for (size_t i = 0U; i < TASKS_MAX; ++i)
1463 {
1464 KernelTask *const task = &m_task_storage[i];
1465 if (task->GetUserStackPtr() == stack)
1466 {
1467 found_task = task;
1468 break;
1469 }
1470 }
1471
1472 return found_task;
1473 }
1474
1480 {
1481 STK_ASSERT(m_task_now != nullptr);
1482
1483 KernelTask *found_task = nullptr;
1484
1485 if (m_task_now->IsMemoryOfSP(SP))
1486 {
1487 found_task = m_task_now;
1488 }
1489 else
1490 {
1491 for (size_t i = 0U; i < TASKS_MAX; ++i)
1492 {
1493 KernelTask *const task = &m_task_storage[i];
1494
1495 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
1497 {
1498 if (!task->IsBusy())
1499 {
1500 continue;
1501 }
1502 }
1503
1504 if (task->IsMemoryOfSP(SP))
1505 {
1506 found_task = task;
1507 break;
1508 }
1509 }
1510 }
1511
1512 return found_task;
1513 }
1514
1519 void RemoveTask(KernelTask *task)
1520 {
1521 STK_ASSERT(task != nullptr);
1522
1523 #if STK_SEGGER_SYSVIEW
1524 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
1525 #endif
1526
1527 // notify task about pending exit
1528 task->GetUserTask()->OnExit();
1529
1530 m_strategy.RemoveTask(task);
1531 task->Unbind();
1532 }
1533
1544 __stk_attr_noinline void OnStart(Stack *&active) override
1545 {
1546 STK_ASSERT(m_strategy.GetSize() != 0);
1547
1548 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
1549 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1550 {
1551 for (size_t i = 0U; i < TASKS_MAX; ++i)
1552 {
1553 KernelTask *const task = &m_task_storage[i];
1554
1555 if (task->IsSleeping())
1556 {
1557 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1558 {
1559 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1560
1561 // notify strategy that task is sleeping
1562 m_strategy.OnTaskSleep(task);
1563 }
1564 }
1565 }
1566 }
1567
1568 // get initial state and first task
1569 {
1571
1572 KernelTask *next = nullptr;
1574
1575 // expecting only SLEEPING or SWITCHING states
1577
1579 {
1580 m_task_now = next;
1581
1582 active = next->GetUserStackPtr();
1583
1585 {
1586 next->HrtOnSwitchedIn();
1587 }
1588 }
1589 else
1591 {
1592 // MISRA 5-2-3 deviation: GetNext/GetFirst returns IKernelTask*, all objects in
1593 // the strategy pool are KernelTask instances - downcast is guaranteed safe.
1594 m_task_now = static_cast<KernelTask *>(m_strategy.GetFirst());
1595
1596 active = &m_sleep_trap[0].stack;
1597 }
1598 else
1599 {
1600 // unexpected state
1602 }
1603 }
1604
1605 // is in running state
1607
1608 #if STK_SEGGER_SYSVIEW
1609 SEGGER_SYSVIEW_OnTaskStartExec(m_task_now->tid);
1610 #endif
1611 }
1612
1619 {
1621 {
1623
1624 // is in stopped state, i.e. is ready to Start() again
1626 }
1627 }
1628
1645 bool OnTick(Stack *&idle, Stack *&active
1646 #if STK_TICKLESS_IDLE
1647 , Timeout &ticks
1648 #endif
1649 ) override
1650 {
1651 #if !STK_TICKLESS_IDLE
1652 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
1653 enum { ticks = 1 };
1654 #endif
1655
1656 // advance internal timestamp
1657 m_service.IncrementTicks(ticks);
1658
1659 // consume elapsed and update to ticks to sleep
1660 #if STK_TICKLESS_IDLE
1661 ticks = (
1662 #else
1663 // notify compiler that we ignore a return value of UpdateTasks
1664 static_cast<void>(
1665 #endif
1666 UpdateTasks(ticks));
1667
1668 // decide on a context switch
1669 return UpdateFsmState(idle, active);
1670 }
1671
1672 void OnTaskSwitch(Word caller_SP) override
1673 {
1674 OnTaskSleep(caller_SP, YIELD_TICKS);
1675 }
1676
1677 void OnTaskSleep(Word caller_SP, Timeout ticks) override
1678 {
1679 KernelTask *const task = FindTaskBySP(caller_SP);
1680 STK_ASSERT(task != nullptr);
1681
1682 // make change to HRT state and sleep time atomic
1683 {
1685
1687 {
1688 task->HrtOnWorkCompleted();
1689 }
1690
1691 if (ticks > 0)
1692 {
1693 task->ScheduleSleep(ticks);
1694 }
1695 }
1696
1697 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1698 task->BusyWaitWhileSleeping();
1699 }
1700
1701 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
1702 {
1703 KernelTask *const task = FindTaskBySP(caller_SP);
1704 STK_ASSERT(task != nullptr);
1705
1706 bool result = true;
1707
1708 // make change to HRT state and sleep time atomic
1709 {
1711
1712 // calculate signed delta (handles wrap-around correctly)
1713 const Ticks delta = timestamp - m_service.m_ticks;
1714
1715 if (delta > 0)
1716 {
1717 task->ScheduleSleep(static_cast<Timeout>(Min(delta, static_cast<Ticks>(INT32_MAX))));
1718 }
1719 else
1720 {
1721 result = false; // deadline already hit or passed
1722 }
1723 }
1724
1725 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1726 task->BusyWaitWhileSleeping();
1727 return result;
1728 }
1729
1731 {
1732 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(task_id));
1733 if (task != nullptr)
1734 {
1736
1737 if (task->IsSleeping())
1738 {
1739 task->Wake();
1740 }
1741 }
1742 }
1743
1744 void OnTaskExit(Stack *stack) override
1745 {
1747 {
1748 KernelTask *const task = FindTaskByStack(stack);
1749 STK_ASSERT(task != nullptr);
1750
1751 // notify kernel to execute removal
1752 task->ScheduleRemoval();
1753 }
1754 else
1755 {
1756 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
1758 }
1759 }
1760
1761 IWaitObject *OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
1762 {
1764 {
1765 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
1766 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
1767 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
1768 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
1769
1770 KernelTask *const task = FindTaskBySP(caller_SP);
1771 STK_ASSERT(task != nullptr);
1772
1773 // configure waiting
1774 task->m_wait_obj->SetupWait(sync_obj, timeout);
1775
1776 // register ISyncObject if not yet
1777 if (sync_obj->GetHead() == nullptr)
1778 {
1779 m_sync_list->LinkBack(sync_obj);
1780 }
1781
1782 // start sleeping infinitely, we rely on a Wake call via WaitObject
1783 task->ScheduleSleep(WAIT_INFINITE);
1784
1785 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
1786 mutex->Unlock();
1787
1788 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1789 task->BusyWaitWhileSleeping();
1790
1791 // re-lock mutex when returning to the task's execution space
1792 mutex->Lock();
1793
1794 return task->m_wait_obj;
1795 }
1796 else
1797 {
1798 STK_ASSERT(false);
1799 return nullptr;
1800 }
1801 }
1802
1803 TId OnGetTid(Word caller_SP) override
1804 {
1805 KernelTask *const task = FindTaskBySP(caller_SP);
1806 STK_ASSERT(task != nullptr);
1807
1808 return task->GetTid();
1809 }
1810
1811 void OnSuspend(bool suspended) override
1812 {
1813 // toggle kernel state
1814 if (suspended)
1815 {
1816 if (m_kstate == KSTATE_RUNNING)
1817 {
1819 }
1820 }
1821 else
1822 {
1823 if (m_kstate == KSTATE_SUSPENDED)
1824 {
1826 }
1827 }
1828
1829 // force yield for a currently active task
1830 if (!m_task_now->IsSleeping())
1831 {
1832 m_task_now->ScheduleSleep(YIELD_TICKS);
1833 }
1834 }
1835
1836 void OnInheritWeight(TId tid, Weight weight)
1837 {
1838 STK_ASSERT(tid != TID_NONE);
1839 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1840
1841 if (weight != NO_WEIGHT)
1842 {
1843 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1844 STK_ASSERT(task != nullptr);
1845
1846 const Weight prev_weight = task->GetWeight();
1847
1848 if (prev_weight < weight)
1849 {
1850 task->SetCurrentWeight(weight);
1851 m_strategy.OnTaskWeightChange(task, prev_weight);
1852 }
1853 }
1854 }
1855
1857 {
1858 STK_ASSERT(tid != TID_NONE);
1859 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1860
1861 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1862 STK_ASSERT(task != nullptr);
1863
1864 const Weight prev_weight = task->GetWeight();
1865
1866 // restore to original or boost from wait objects
1867 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
1868
1869 m_strategy.OnTaskWeightChange(task, prev_weight);
1870 }
1871
1874 Timeout UpdateTasks(const Timeout elapsed_ticks)
1875 {
1876 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
1878 {
1879 UpdateSyncObjects(elapsed_ticks);
1880 }
1881
1882 if (m_request != REQ_NONE)
1883 {
1885 }
1886
1887 return UpdateTaskState(elapsed_ticks);
1888 }
1889
1899 Timeout UpdateTaskState(const Timeout elapsed_ticks)
1900 {
1902
1903 for (size_t i = 0U; i < TASKS_MAX; ++i)
1904 {
1905 KernelTask *const task = &m_task_storage[i];
1906
1907 if (task->IsSleeping())
1908 {
1910 {
1911 // task is pending removal, wait until it is switched out
1912 if (task->IsPendingRemoval())
1913 {
1914 if ((task != m_task_now) ||
1915 ((m_strategy.GetSize() == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
1916 {
1917 RemoveTask(task);
1918 continue;
1919 }
1920 }
1921 }
1922
1923 // deliver sleep event to strategy
1924 // note: only currently scheduled task can be pending to sleep
1925 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1926 {
1927 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1928 {
1929 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1930
1931 // notify strategy that task is sleeping
1932 m_strategy.OnTaskSleep(task);
1933 }
1934 }
1935
1936 // advance sleep time by a tick
1937 task->m_time_sleep += elapsed_ticks;
1938
1939 // deliver sleep event to strategy
1940 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1941 {
1942 // notify strategy that task woke up
1943 if (!task->IsSleeping())
1944 {
1945 m_strategy.OnTaskWake(task);
1946 }
1947 }
1948 }
1949 else
1950 {
1952 {
1953 // in HRT mode we trace how long task spent in active state (doing some work)
1954 if (task->IsBusy())
1955 {
1956 task->m_hrt[0].duration += elapsed_ticks;
1957
1958 // check if deadline is missed (HRT failure)
1959 if (task->HrtIsDeadlineMissed(task->m_hrt[0].duration))
1960 {
1961 // report deadline overrun to a strategy which supports overrun recovery
1962 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
1963 {
1964 if (!m_strategy.OnTaskDeadlineMissed(task))
1965 {
1966 // report failure if it could not be recovered by the scheduling strategy
1967 task->HrtHardFailDeadline(&m_platform);
1968 }
1969 }
1970 else
1971 {
1972 task->HrtHardFailDeadline(&m_platform);
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979 // get the number ticks the driver has to keep CPU in Idle
1981 {
1982 if ((sleep_ticks > 1) && task->IsBusy())
1983 {
1984 sleep_ticks = task->GetSleepTicks(sleep_ticks);
1985 }
1986 }
1987 }
1988
1989 return sleep_ticks;
1990 }
1991
1994 void UpdateSyncObjects(const Timeout elapsed_ticks)
1995 {
1996 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
1997
1998 while (itr != nullptr)
1999 {
2000 ISyncObject::ListEntryType *const next = itr->GetNext();
2001
2002 if (!static_cast<ISyncObject *>(itr)->Tick(elapsed_ticks))
2003 {
2004 m_sync_list->Unlink(itr);
2005 }
2006
2007 itr = next;
2008 }
2009 }
2010
2014 {
2015 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2016 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2018 {
2019 // process serialized AddTask request made from another active task, requesting process
2020 // is currently waiting due to SwitchToNext()
2021 if ((m_request & REQ_ADD_TASK) != 0U)
2022 {
2024
2025 for (size_t i = 0U; i < TASKS_MAX; ++i)
2026 {
2027 KernelTask *const task = &m_task_storage[i];
2028
2029 if (task->m_srt[0].add_task_req != nullptr)
2030 {
2031 AllocateAndAddNewTask(task->m_srt[0].add_task_req->user_task);
2032
2033 task->m_srt[0].add_task_req = nullptr;
2034 __stk_full_memfence();
2035 }
2036 }
2037 }
2038 }
2039 }
2040
2045 EFsmEvent FetchNextEvent(KernelTask *&next)
2046 {
2048
2049 // try getting next task for scheduling
2050 next = static_cast<KernelTask *>(m_strategy.GetNext());
2051
2052 // sleep-aware strategy returns nullptr if no active tasks available
2053 if (next != nullptr)
2054 {
2055 // strategy must provide active-only task
2056 STK_ASSERT(!next->IsSleeping());
2057
2058 // if was sleeping, process wake event first
2060 }
2061 // start sleeping
2062 else
2063 {
2065 {
2066 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2067 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2068 if (m_strategy.GetSize() == 0U)
2069 {
2070 next = nullptr;
2071 type = FSM_EVENT_EXIT;
2072 }
2073 }
2074 }
2075
2076 return type;
2077 }
2078
2083#ifdef _STK_UNDER_TEST
2084 virtual
2085#endif
2086 EFsmState GetNewFsmState(KernelTask *&next)
2087 {
2089 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2090 }
2091
2097 bool UpdateFsmState(Stack *&idle, Stack *&active)
2098 {
2099 KernelTask *const now = m_task_now, *next = nullptr;
2100 bool switch_context = false;
2101
2102 const EFsmState new_state = GetNewFsmState(next);
2103
2104 switch (new_state)
2105 {
2107 switch_context = StateSwitch(now, next, idle, active);
2108 m_fsm_state = new_state;
2109 break;
2110 case FSM_STATE_SLEEPING:
2111 switch_context = StateSleep(now, next, idle, active);
2112 m_fsm_state = new_state;
2113 break;
2114 case FSM_STATE_WAKING:
2115 switch_context = StateWake(now, next, idle, active);
2116 m_fsm_state = new_state;
2117 break;
2118 case FSM_STATE_EXITING:
2119 switch_context = StateExit(now, next, idle, active);
2120 m_fsm_state = new_state;
2121 break;
2122 case FSM_STATE_NONE:
2123 break; // valid intermittent non-persisting state: no-transition
2124 case FSM_STATE_MAX:
2125 default: // invalid state value
2127 break;
2128 }
2129
2130 return switch_context;
2131 }
2132
2140 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2141 {
2142 STK_ASSERT(now != nullptr);
2143 STK_ASSERT(next != nullptr);
2144
2145 bool switch_context = false;
2146
2147 // if equal: do not switch context because task did not change
2148 if (next != now)
2149 {
2150 idle = now->GetUserStackPtr();
2151 active = next->GetUserStackPtr();
2152
2153 // if stack memory is exceeded these assertions will be hit
2154 if (now->IsBusy())
2155 {
2156 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2157 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2158 }
2159 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2160
2161 m_task_now = next;
2162
2164 {
2165 if (now->m_hrt[0].done)
2166 {
2167 now->HrtOnSwitchedOut(&m_platform);
2168 next->HrtOnSwitchedIn();
2169 }
2170 }
2171
2172 #if STK_SEGGER_SYSVIEW
2173 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SWITCH);
2174 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2175 #endif
2176
2177 switch_context = true;
2178 }
2179
2180 return switch_context;
2181 }
2182
2190 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2191 {
2192 STK_UNUSED(now);
2193
2194 STK_ASSERT(next != nullptr);
2195
2196 idle = &m_sleep_trap[0].stack;
2197 active = next->GetUserStackPtr();
2198
2199 // if stack memory is exceeded these assertions will be hit
2201 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2202
2203 m_task_now = next;
2204
2205 #if STK_SEGGER_SYSVIEW
2206 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2207 #endif
2208
2210 {
2211 next->HrtOnSwitchedIn();
2212 }
2213
2214 return true; // switch context
2215 }
2216
2224 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2225 {
2226 STK_UNUSED(next);
2227
2228 STK_ASSERT(now != nullptr);
2229 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
2230
2231 idle = now->GetUserStackPtr();
2232 active = &m_sleep_trap[0].stack;
2233
2234 m_task_now = static_cast<KernelTask *>(m_strategy.GetFirst());
2235
2236 #if STK_SEGGER_SYSVIEW
2237 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2238 #endif
2239
2241 {
2242 if (!now->IsPendingRemoval())
2243 {
2244 now->HrtOnSwitchedOut(&m_platform);
2245 }
2246 }
2247
2248 return true; // switch context
2249 }
2250
2259 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2260 {
2261 STK_UNUSED(now);
2262 STK_UNUSED(next);
2263
2265 {
2266 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
2267 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
2268
2269 idle = nullptr;
2270 active = &m_exit_trap[0].stack;
2271
2272 m_task_now = nullptr;
2273
2274 m_platform.Stop();
2275 }
2276 else
2277 {
2278 STK_UNUSED(idle);
2279 STK_UNUSED(active);
2280 }
2281
2282 return false;
2283 }
2284
2288 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
2289
2295 {
2298 }
2299
2300#if STK_SEGGER_SYSVIEW
2305 void SendTaskTraceInfo(KernelTask *task)
2306 {
2307 STK_ASSERT(task->IsBusy());
2308
2309 SEGGER_SYSVIEW_TASKINFO info =
2310 {
2311 .TaskID = task->GetUserStackPtr()->tid,
2312 .sName = task->GetUserTask()->GetTraceName(),
2313 .Prio = 0,
2314 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
2315 .StackSize = task->GetUserTask()->GetStackSizeBytes()
2316 };
2317 SEGGER_SYSVIEW_SendTaskInfo(&info);
2318 }
2319#endif
2320
2321 // Kernel modes:
2322 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
2323 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
2324 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
2325 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
2326 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
2327
2328 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
2330
2331 // If hit here: Kernel mode must be assigned.
2332 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
2333
2334 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
2335 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
2336 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
2337
2338 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
2339 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
2340 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
2341
2342 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
2343 // which destroys the precise periodicity HRT depends on.
2344 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
2345 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
2346
2347 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
2348 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
2349 !TStrategy::PRIORITY_INHERITANCE_API);
2350
2355
2370
2386
2393
2394 KernelService m_service;
2395 TPlatform m_platform;
2396 TStrategy m_strategy;
2397 KernelTask *m_task_now;
2399 SleepTrapStack m_sleep_trap[1];
2402 volatile uint8_t m_request;
2405
2407 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
2412 };
2413
2415};
2416
2417} // namespace stk
2418
2419#endif /* STK_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:610
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:440
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:174
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:411
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:254
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:384
#define STK_STATIC_ASSERT_DESC(X, DESC)
Compile-time assertion with a custom error description. Produces a compilation error if X is false.
Definition stk_defs.h:431
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
Definition stk_defs.h:458
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:158
Contains helper implementations which simplify user-side code.
Earliest Deadline First (EDF) task-switching strategy (stk::SwitchStrategyEDF).
Fixed-priority preemptive task-switching strategy with round-robin within each priority level (stk::S...
Rate-Monotonic (RM) and Deadline-Monotonic (DM) task-switching strategies (stk::SwitchStrategyMonoton...
Round-Robin task-switching strategy (stk::SwitchStrategyRoundRobin / stk::SwitchStrategyRR).
Smooth Weighted Round-Robin task-switching strategy (stk::SwitchStrategySmoothWeightedRoundRobin / st...
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:115
@ TRACE_EVENT_SLEEP
Task entered sleep / blocked state.
Definition stk_common.h:105
@ TRACE_EVENT_SWITCH
Task context switch event (task became active).
Definition stk_common.h:104
static constexpr ITask * GetUserTaskFromTid(TId task_id) noexcept
Get task instance from its identifier.
Definition stk_arch.h:501
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int64_t Ticks
Ticks value.
Definition stk_common.h:130
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:639
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:74
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:73
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:75
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:75
static constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:199
static constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:194
@ PERIODICITY_DEFAULT
Default periodicity (microseconds), 1 millisecond.
Definition stk_common.h:84
@ PERIODICITY_MAX
Maximum periodicity (microseconds), 99 milliseconds (note: this value is the highest working on a rea...
Definition stk_common.h:83
Timeout GetInitialSleepTicks()
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:177
@ SYS_TASK_ID_EXIT
Exit trap.
Definition stk_common.h:94
@ SYS_TASK_ID_SLEEP
Sleep trap.
Definition stk_common.h:93
static constexpr T Min(T a, T b)
Compile-time minimum of two values.
Definition stk_defs.h:633
static constexpr TId GetTidFromUserTask(const ITask *task) noexcept
Get task identifier from ITask instance.
Definition stk_arch.h:495
uint64_t Cycles
Cycles value.
Definition stk_common.h:140
Word TId
Definition stk_common.h:120
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:145
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:34
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
Definition stk_common.h:46
@ KERNEL_SYNC
Synchronization support (see Event).
Definition stk_common.h:45
@ KERNEL_HRT
Hard Real-Time (HRT) behavior (tasks are scheduled periodically and have an execution deadline,...
Definition stk_common.h:44
@ KERNEL_STATIC
All tasks are static and can not exit.
Definition stk_common.h:42
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
Definition stk_common.h:43
@ KERNEL_PANIC_BAD_MODE
Kernel is in bad/unsupported mode for the current operation.
Definition stk_common.h:63
@ KERNEL_PANIC_BAD_STATE
Kernel entered unexpected (bad) state.
Definition stk_common.h:62
Memory-related primitives.
__stk_forceinline void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:434
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:106
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
__stk_forceinline T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:379
void OnStop() override
Called by the platform driver after a scheduler stop (all tasks have exited).
Definition stk.h:1618
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2097
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1329
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1413
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:1744
void OnTaskSleepCancel(TId task_id)
Definition stk.h:1730
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1255
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:1458
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:2354
~Kernel()=default
Destructor.
bool OnTick(Stack *&idle, Stack *&active, Timeout &ticks) override
Process one scheduler tick. Called from the platform timer/tick ISR.
Definition stk.h:1645
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:1811
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1066
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2086
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel before Start().
Definition stk.h:1041
StackMemoryWrapper< STACK_SIZE_MIN > ExitTrapStackMemory
Stack memory wrapper type for the exit trap.
Definition stk.h:97
void OnRestoreWeight(TId tid, ISyncObject *sobj)
Definition stk.h:1856
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:1544
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:2190
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:1479
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1295
static constexpr bool IsHrtMode()
Definition stk.h:2324
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:977
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:2392
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1269
StackMemoryWrapper<((32U))> SleepTrapStackMemory
Stack memory wrapper type for the sleep trap.
Definition stk.h:91
size_t EnumerateKernelTasks(ArrayView< IKernelTask * > tasks) override
Enumerate kernel tasks.
Definition stk.h:1151
static constexpr bool IsSyncMode()
Definition stk.h:2325
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance.
Definition stk.h:1437
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1287
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:1836
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1131
void OnTaskSleep(Word caller_SP, Timeout ticks) override
Called by Thread process (via IKernelService::Sleep) for exclusion of the calling process from schedu...
Definition stk.h:1677
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1203
static constexpr bool IsTicklessMode()
Definition stk.h:2326
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:1519
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1369
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1247
ERequest
Bitmask flags for pending inter-task requests that must be processed by the kernel on the next tick (...
Definition stk.h:104
IWaitObject * OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
Called from the Thread process when task needs to wait.
Definition stk.h:1761
bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Exits from scheduling.
Definition stk.h:2259
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1238
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1384
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:1672
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:940
void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Allocate new instance of KernelTask and add it into the HRT scheduling process.
Definition stk.h:1399
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:1803
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1175
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:1874
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:2294
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:2288
static constexpr bool IsDynamicMode()
Definition stk.h:2323
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1243
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2140
void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc) override
Register a task for hard real-time (HRT) scheduling.
Definition stk.h:1016
Kernel()
Construct the kernel with all storage zero-initialized and the request flag set to ~0 (indicating uni...
Definition stk.h:907
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2013
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:2224
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, advance sleep timers, and track HRT durations.
Definition stk.h:1899
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:1994
static constexpr bool IsStaticMode()
Definition stk.h:2322
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1230
bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
Called by Thread process (via IKernelService::SleepUntil) for exclusion of the calling process from s...
Definition stk.h:1701
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1094
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2045
Internal per-slot kernel descriptor that wraps a user ITask instance.
Definition stk.h:121
Weight GetCurrentWeight() const override
Get current (run-time) scheduling weight.
Definition stk.h:238
KernelTask()
Construct a free (unbound) task slot. All fields set to zero/null.
Definition stk.h:152
void ScheduleSleep(Timeout ticks)
Put the task into a sleeping state for the specified number of ticks.
Definition stk.h:680
Timeout GetSleepTicks(Timeout sleep_ticks)
Definition stk.h:307
TId GetTid() const
Get task identifier.
Definition stk.h:185
Stack GetUserStack() const
Get stack descriptor for this task slot.
Definition stk.h:170
EStateFlags
Bitmask of transient state flags. Set by the task or the kernel and consumed (cleared) during UpdateT...
Definition stk.h:129
@ STATE_REMOVE_PENDING
Task returned from its Run function; slot will be freed on the next tick (KERNEL_DYNAMIC only).
Definition stk.h:131
@ STATE_SLEEP_PENDING
Task called Sleep/SleepUntil/Yield; strategy's OnTaskSleep() will be invoked on the next tick (sleep-...
Definition stk.h:132
@ STATE_NONE
No pending state flags.
Definition stk.h:130
Timeout GetHrtPeriodicity() const override
Get HRT scheduling periodicity.
Definition stk.h:254
friend class Kernel
Definition stk.h:122
bool HrtIsDeadlineMissed(Timeout duration) const
Check if deadline missed.
Definition stk.h:666
SrtInfo m_srt[STK_ALLOCATE_COUNT< TMode, KERNEL_HRT, 0U, 1U >::Value]
SRT metadata. Zero-size (no memory) in KERNEL_HRT mode.
Definition stk.h:716
void ScheduleRemoval()
Schedule the removal of the task from the kernel on next tick.
Definition stk.h:561
Stack m_stack
Stack descriptor (SP register value + access mode + optional tid).
Definition stk.h:713
void Bind(TPlatform *platform, ITask *user_task)
Bind this slot to a user task: set access mode, task ID, and initialize the stack.
Definition stk.h:507
~KernelTask()=default
Destructor.
Weight m_rt_weight[STK_ALLOCATE_COUNT< TStrategy::WEIGHT_API, 1U, 1U, 0U >::Value]
Run-time weight for weighted-round-robin scheduling. Zero-size for unweighted strategies.
Definition stk.h:718
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:643
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:597
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:714
void BusyWaitWhileSleeping() const
Block further execution of the task's context while in sleeping state.
Definition stk.h:699
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:712
Timeout GetHrtRelativeDeadline() const override
Get remaining HRT deadline (ticks left before the deadline expires).
Definition stk.h:292
void SetCurrentWeight(Weight weight) override
Update the run-time scheduling weight (weighted strategies only).
Definition stk.h:202
bool IsBusy() const
Check whether this slot is bound to a user task.
Definition stk.h:175
bool IsSleeping() const override
Check whether this task is currently sleeping (waiting for a tick or a wake event).
Definition stk.h:180
Stack * GetUserStackPtr()
Get pointer to user Stack.
Definition stk.h:710
HrtInfo m_hrt[STK_ALLOCATE_COUNT< TMode, KERNEL_HRT, 1U, 0U >::Value]
HRT metadata. Zero-size (no memory) in non-HRT mode.
Definition stk.h:717
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:657
void Wake() override
Wake this task on the next scheduling tick.
Definition stk.h:191
Weight GetWeight() const override
Get static scheduling weight from the user task.
Definition stk.h:213
volatile Timeout m_time_sleep
Sleep countdown: negative while sleeping (absolute value = ticks remaining), zero when awake.
Definition stk.h:715
bool IsPendingRemoval() const
Check if task is pending removal.
Definition stk.h:578
Timeout GetHrtDeadline() const override
Get absolute HRT deadline (ticks elapsed since task was activated).
Definition stk.h:273
void HrtOnSwitchedOut(IPlatform *)
Called when task is switched out from the scheduling process.
Definition stk.h:623
void Unbind()
Reset this slot to the free (unbound) state, clearing all scheduling metadata.
Definition stk.h:536
void HrtOnSwitchedIn()
Called when task is switched into the scheduling process.
Definition stk.h:617
bool IsMemoryOfSP(Word SP) const
Check if Stack Pointer (SP) belongs to this task.
Definition stk.h:583
ITask * GetUserTask() override
Get bound user task.
Definition stk.h:165
WaitObject m_wait_obj[STK_ALLOCATE_COUNT< TMode, KERNEL_SYNC, 1U, 0U >::Value]
Embedded wait object for synchronization. Zero-size (no memory) if KERNEL_SYNC is not set.
Definition stk.h:719
Payload for an in-flight AddTask() request issued by a running task.
Definition stk.h:144
ITask * user_task
User task to add. Must remain valid for the lifetime of its kernel slot.
Definition stk.h:145
Per-task soft real-time (SRT) metadata.
Definition stk.h:352
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:358
AddTaskRequest * add_task_req
Definition stk.h:368
Per-task Hard Real-Time (HRT) scheduling metadata.
Definition stk.h:376
void Clear()
Clear all fields, ready for slot re-use or re-activation.
Definition stk.h:382
volatile bool done
Set to true when the task signals work completion (via Yield() or on exit). Triggers HrtOnSwitchedOut...
Definition stk.h:393
Timeout deadline
Maximum allowed active duration in ticks (relative to switch-in). Exceeding this triggers OnDeadlineM...
Definition stk.h:391
Timeout periodicity
Activation period in ticks: the task is re-activated every this many ticks.
Definition stk.h:390
Timeout duration
Ticks spent in the active (non-sleeping) state in the current period. Incremented by UpdateTaskState(...
Definition stk.h:392
Concrete implementation of IWaitObject, embedded in each KernelTask slot.
Definition stk.h:403
bool IsWaiting() const
Check if busy with waiting.
Definition stk.h:435
Timeout m_time_wait
Ticks remaining until timeout. Decremented each tick; WAIT_INFINITE means no timeout.
Definition stk.h:500
void Wake(bool timeout) override
Wake the waiting task (called by ISyncObject when it signals).
Definition stk.h:442
~WaitObject()=default
Destructor.
bool Tick(Timeout elapsed_ticks) override
Advance the timeout countdown by one tick.
Definition stk.h:461
bool IsTimeout() const override
Check whether the wait expired due to timeout.
Definition stk.h:430
void SetupWait(ISyncObject *sync_obj, Timeout timeout)
Configure and arm this wait object for a new wait operation.
Definition stk.h:486
TId GetTid() const override
Get the TId of the task that owns this wait object.
Definition stk.h:425
volatile bool m_timeout
true if the wait expired due to timeout rather than a Wake() signal.
Definition stk.h:499
ISyncObject * m_sync_obj
Sync object this wait is registered with, or NULL when not waiting.
Definition stk.h:498
KernelTask * m_task
Back-pointer to the owning KernelTask. Set once at construction; never changes.
Definition stk.h:497
Payload stored in the sync object's kernel-side list entry while a task is waiting.
Definition stk.h:418
ISyncObject * sync_obj
Sync object whose Tick() will be called each kernel tick.
Definition stk.h:419
KernelService()
Construct an uninitialized service instance (m_platform = null, m_ticks = 0).
Definition stk.h:864
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:819
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:799
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:892
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:742
friend class Kernel
Definition stk.h:731
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:759
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:891
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:736
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:791
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:832
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:775
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:852
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:844
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:740
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:738
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:744
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:734
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:885
IWaitObject * Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
Definition stk.h:806
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:877
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2364
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:2365
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:2368
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2367
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2380
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:2384
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:2381
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2383
RAII guard that enters the critical section on construction and exits it on destruction.
Definition stk_arch.h:240
Lightweight, non-owning view over a contiguous sequence of elements.
Definition stk_common.h:226
size_t GetSize() const
Get number of elements in the view.
Definition stk_common.h:249
Stack descriptor.
Definition stk_common.h:280
EAccessMode access_mode
Hardware access mode of the owning task (see EAccessMode).
Definition stk_common.h:282
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Wait object.
Definition stk_common.h:335
Synchronization object.
Definition stk_common.h:429
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:441
virtual void AddWaitObject(IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:447
DLHeadType ListHeadType
List head type for ISyncObject elements.
Definition stk_common.h:436
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:214
Interface for mutex synchronization primitive.
Definition stk_common.h:532
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:589
virtual EAccessMode GetAccessMode() const =0
Get hardware access mode of the user task.
TId GetId() const
Get task Id set by application.
Definition stk_helper.h:234
virtual void OnExit()
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
Definition stk_common.h:628
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:661
Interface for a platform driver.
Definition stk_common.h:753
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
Definition stk_common.h:761
Interface for a task switching strategy implementation.
Interface for the implementation of the kernel of the scheduler. It supports Soft and Hard Real-Time ...
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
static constexpr size_t Value
Definition stk_defs.h:570
Adapts an externally-owned stack memory array to the IStackMemory interface.
Definition stk_helper.h:137
StackMemoryDef< _StackSize >::Type MemoryType
Definition stk_helper.h:142
DLEntryType * GetNext()
Get the next entry in the list.
DLHeadType * GetHead()
Get the list head this entry currently belongs to.