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 override { 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 Weight static_weight;
216
217 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
218 {
219 if (m_rt_weight[0] != NO_WEIGHT)
220 {
221 static_weight = m_rt_weight[0];
222 }
223 else
224 {
225 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
226 {
227 static_weight = m_user->GetWeight();
228 }
229 else
230 {
231 static_weight = DEFAULT_WEIGHT;
232 }
233 }
234 }
235 else if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
236 {
237 static_weight = m_user->GetWeight();
238 }
239 else
240 {
241 static_weight = DEFAULT_WEIGHT;
242 }
243
244 return static_weight;
245 }
246
252 Weight GetCurrentWeight() const override
253 {
254 Weight cur_weight;
255
256 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
257 {
258 cur_weight = m_rt_weight[0];
259 }
260 else
261 {
262 cur_weight = DEFAULT_WEIGHT;
263 }
264
265 return cur_weight;
266 }
267
272 Timeout GetHrtPeriodicity() const override
273 {
275
276 Timeout to;
277
279 {
280 to = m_hrt[0].periodicity;
281 }
282 else
283 {
284 to = 0;
285 }
286
287 return to;
288 }
289
295 Timeout GetHrtDeadline() const override
296 {
298
299 Timeout deadline;
300
302 {
303 deadline = m_hrt[0].deadline;
304 }
305 else
306 {
307 deadline = 0;
308 }
309
310 return deadline;
311 }
312
319 {
322
323 Timeout relative_deadline;
324
326 {
327 relative_deadline = (m_hrt[0].deadline - m_hrt[0].duration);
328 }
329 else
330 {
331 relative_deadline = 0;
332 }
333
334 return relative_deadline;
335 }
336
338 {
339 // note: task sleep time is negative
341
343 {
344 // likely task is sleeping during sync operation (see Wait)
345 if (m_wait_obj->IsWaiting())
346 {
347 // note: sync wait time is positive
348 task_sleep = m_wait_obj->m_time_wait;
349
350 // we shall account for only valid time (when task is waiting during sync operation)
351 if (task_sleep > NO_WAIT)
352 {
353 sleep_ticks = Min(sleep_ticks, task_sleep);
354 }
355 }
356 else
357 {
358 sleep_ticks = Min(sleep_ticks, task_sleep);
359 }
360 }
361 else
362 {
363 sleep_ticks = Min(sleep_ticks, task_sleep);
364 }
365
366 // clamp to [1, STK_TICKLESS_TICKS_MAX] range
367 return Max<Timeout>(1, sleep_ticks);
368 }
369
370 protected:
375
381 struct SrtInfo
382 {
384 {}
385
388 void Clear()
389 {
390 add_task_req = nullptr;
391 }
392
399 };
400
405 struct HrtInfo
406 {
407 HrtInfo() : periodicity(0), deadline(0), duration(0), done(false)
408 {}
409
412 void Clear()
413 {
414 periodicity = 0;
415 deadline = 0;
416 duration = 0;
417 done = false;
418 }
419
423 volatile bool done;
424 };
425
432 struct WaitObject final : public IWaitObject
433 {
434 explicit WaitObject() : m_task(nullptr), m_sync_obj(nullptr), m_timeout(false), m_time_wait(0)
435 {}
436
441
448 {
450 };
451
455 TId GetTid() const override { return m_task->GetTid(); }
456
460 bool IsTimeout() const override { return m_timeout; }
461
465 bool IsWaiting() const { return (m_sync_obj != nullptr); }
466
472 void Wake(bool timeout) override
473 {
475
476 m_timeout = timeout;
477 m_time_wait = 0;
478
479 m_sync_obj->RemoveWaitObject(this);
480 m_sync_obj = nullptr;
481
482 return m_task->Wake();
483 }
484
491 bool Tick(Timeout elapsed_ticks) override
492 {
494 {
495 if (!m_timeout)
496 {
497 m_time_wait -= elapsed_ticks;
498
499 if (m_time_wait <= 0)
500 {
501 m_timeout = true;
502 }
503 }
504 }
505
506 return !m_timeout;
507 }
508
516 void SetupWait(ISyncObject *sync_obj, Timeout timeout)
517 {
519
520 m_sync_obj = sync_obj;
521 m_time_wait = timeout;
522 m_timeout = false;
523
524 sync_obj->AddWaitObject(this);
525 }
526
529 volatile bool m_timeout;
531 };
532
537 void Bind(TPlatform *platform, ITask *user_task)
538 {
539 // set access mode for this stack
540 m_stack.access_mode = user_task->GetAccessMode();
541
542 // set task id for tracking purpose
543 #if STK_NEED_TASK_ID
544 m_stack.tid = user_task->GetId();
545 #endif
546
547 // init stack of the user task
548 platform->InitStack(STACK_USER_TASK, &m_stack, user_task, user_task);
549
550 // bind user task
551 m_user = user_task;
552
553 // initialize current weight to NO_WEIGHT for priority inheritance mechanism
554 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
555 {
557 }
558 }
559
563 void Unbind()
564 {
566 {
567 // should be freed from waiting on task exit
568 STK_ASSERT(!m_wait_obj->IsWaiting());
569 }
570
571 m_user = nullptr;
572 m_stack = {};
574 m_time_sleep = 0;
575
577 {
578 m_hrt[0].Clear();
579 }
580 else
581 {
582 m_srt->Clear();
583 }
584 }
585
589 {
590 // make this task sleeping to switch it out from scheduling process
592
593 // mark it as done HRT task
595 {
597 }
598
599 // mark it as pending for removal
601 }
602
605 bool IsPendingRemoval() const { return ((m_state & STATE_REMOVE_PENDING) != 0U); }
606
610 bool IsMemoryOfSP(Word SP) const
611 {
612 const Word start = hw::PtrToWord(m_user->GetStack());
613 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
614
615 return (SP >= start) && (SP <= end);
616 }
617
624 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
625 {
626 STK_ASSERT(periodicity_tc > 0);
627 STK_ASSERT(deadline_tc > 0);
628 STK_ASSERT(start_delay_tc >= 0);
629 STK_ASSERT(periodicity_tc < INT32_MAX);
630 STK_ASSERT(deadline_tc < INT32_MAX);
631
632 m_hrt[0].periodicity = periodicity_tc;
633 m_hrt[0].deadline = deadline_tc;
634
635 if (start_delay_tc > 0)
636 {
637 ScheduleSleep(start_delay_tc);
638 }
639 }
640
645
650 {
651 const Timeout duration = m_hrt[0].duration;
652
653 STK_ASSERT(duration >= 0);
654
655 const Timeout sleep = m_hrt[0].periodicity - duration;
656 if (sleep > 0)
657 {
658 ScheduleSleep(sleep);
659 }
660
661 m_hrt[0].duration = 0;
662 m_hrt[0].done = false;
663 }
664
670 {
671 const Timeout duration = m_hrt[0].duration;
672
673 STK_ASSERT(duration >= 0);
675
676 m_user->OnDeadlineMissed(duration);
677 platform->ProcessHardFault();
678 }
679
684 {
685 m_hrt[0].done = true;
686 __stk_full_memfence();
687 }
688
692 bool HrtIsDeadlineMissed(Timeout duration) const
693 {
694 return (duration > m_hrt[0].deadline);
695 }
696
707 {
708 STK_ASSERT(ticks > 0);
709
710 // set state first as kernel checks it when task IsSleeping
711 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
712 {
713 if (!IsSleeping())
714 {
716 }
717 }
718
719 m_time_sleep = -ticks;
720 __stk_full_memfence();
721 }
722
726 {
727 while (IsSleeping())
728 {
729 __stk_relax_cpu();
730 }
731 }
732
737
740 volatile uint32_t m_state;
746 };
747
755 class KernelService final : public IKernelService
756 {
757 friend class Kernel;
758
759 public:
760 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
761
762 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
763
764 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
765
766 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
767
768 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
769
770 void Delay(Timeout ticks) override
771 {
773 STK_ASSERT(ticks >= 0);
774
775 Ticks now = GetTicks();
776 const Ticks deadline = now + ticks;
777 STK_ASSERT(deadline >= now);
778
779 for (; now < deadline; now = GetTicks())
780 {
781 __stk_relax_cpu();
782 }
783 }
784
785 void Sleep(Timeout ticks) override
786 {
788 STK_ASSERT(ticks >= 0);
789
791 {
792 m_kernel->m_platform.Sleep(ticks);
793 }
794 else
795 {
796 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
797 STK_ASSERT(false);
798 }
799 }
800
801 bool SleepUntil(Ticks timestamp) override
802 {
804
806 {
807 return m_kernel->m_platform.SleepUntil(timestamp);
808 }
809 else
810 {
811 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
812 STK_ASSERT(false);
813 return false;
814 }
815 }
816
817 void SleepCancel(TId task_id) override
818 {
820 {
821 m_kernel->OnTaskSleepCancel(task_id);
822 }
823 }
824
825 void SwitchToNext() override
826 {
828
829 m_kernel->m_platform.SwitchToNext();
830 }
831
832 IWaitObject *Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
833 {
835 {
836 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
837 }
838 else
839 {
840 STK_ASSERT(false);
841 return nullptr;
842 }
843 }
844
845 Timeout Suspend() override
846 {
848 {
849 return m_kernel->m_platform.Suspend();
850 }
851 else
852 {
853 STK_ASSERT(false);
854 return 0;
855 }
856 }
857
858 void Resume(Timeout elapsed_ticks) override
859 {
861 {
862 return m_kernel->m_platform.Resume(elapsed_ticks);
863 }
864 else
865 {
866 STK_ASSERT(false);
867 }
868 }
869
870 void InheritWeight(TId tid, Weight weight) override
871 {
872 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
873 {
874 m_kernel->OnInheritWeight(tid, weight);
875 }
876 }
877
878 void RestoreWeight(TId tid, ISyncObject *sobj) override
879 {
880 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
881 {
882 m_kernel->OnRestoreWeight(tid, sobj);
883 }
884 }
885
886 private:
890 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
891 {}
892
897
903 void Initialize(Kernel *kernel)
904 {
905 m_kernel = kernel;
906 }
907
911 void IncrementTicks(Ticks advance)
912 {
913 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
915 }
916
918 volatile Ticks m_ticks;
919 };
920
921public:
924 static constexpr size_t TASKS_MAX = TSize;
925
935 {
936 #ifdef _DEBUG
937 // TPlatform must inherit IPlatform
938 IPlatform *platform = &m_platform;
939 STK_UNUSED(platform);
940
941 // TStrategy must inherit ITaskSwitchStrategy
942 ITaskSwitchStrategy *strategy = &m_strategy;
943 STK_UNUSED(strategy);
944 #endif
945
946 #if !STK_TICKLESS_IDLE
947 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
948 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
949 #endif
950 }
951
956
966 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
967 {
968 STK_ASSERT(resolution_us != 0);
969 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
971
972 // reinitialize key state variables
973 m_task_now = nullptr;
976
977 // exit trap is required only for KERNEL_DYNAMIC mode
978 Stack *exit_trap;
980 {
981 exit_trap = &m_exit_trap[0].stack;
982 }
983 else
984 {
985 exit_trap = nullptr;
986 }
987
988 m_service.Initialize(this);
989 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
990
991 // now ready to Start()
993 }
994
1003 __stk_attr_noinline void AddTask(ITask *user_task) override
1004 {
1006 {
1007 STK_ASSERT(user_task != nullptr);
1009
1010 // when started the operation must be serialized by switching out from processing until
1011 // kernel processes this request
1012 if (IsStarted())
1013 {
1015 {
1016 RequestAddTask(user_task);
1017 }
1018 else
1019 {
1020 STK_ASSERT(false);
1021 }
1022 }
1023 else
1024 {
1025 AllocateAndAddNewTask(user_task);
1026 }
1027 }
1028 else
1029 {
1030 STK_ASSERT(false);
1031 }
1032 }
1033
1042 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1043 Timeout start_delay_tc) override
1044 {
1046 {
1047 STK_ASSERT(user_task != nullptr);
1050
1051 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1052 }
1053 else
1054 {
1055 STK_ASSERT(false);
1056 }
1057 }
1058
1067 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1068 {
1070 {
1071 STK_ASSERT(user_task != nullptr);
1073
1074 KernelTask *const task = FindTaskByUserTask(user_task);
1075 if (task != nullptr)
1076 {
1077 RemoveTask(task);
1078 }
1079 }
1080 else
1081 {
1082 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1083 STK_ASSERT(false);
1084 }
1085 }
1086
1093 {
1095 {
1096 STK_ASSERT(user_task != nullptr);
1098
1100
1101 KernelTask *const task = FindTaskByUserTask(user_task);
1102 if (task != nullptr)
1103 {
1104 task->ScheduleRemoval();
1105 }
1106 }
1107 else
1108 {
1109 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1110 STK_ASSERT(false);
1111 }
1112 }
1113
1120 void SuspendTask(ITask *user_task, bool &suspended) override
1121 {
1122 STK_ASSERT(user_task != nullptr);
1123
1124 bool self = false;
1125
1126 // avoid race with OnTick
1127 {
1129
1130 KernelTask *const task = FindTaskByUserTask(user_task);
1131 STK_ASSERT(task != nullptr);
1132
1133 // only suspend if the task is currently awake: if it is already sleeping
1134 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1135 // that would corrupt the original sleep state and, for sync-object waits,
1136 // would interfere with WaitObject::Tick()
1137 suspended = !task->IsSleeping();
1138 if (suspended == true)
1139 {
1140 task->ScheduleSleep(WAIT_INFINITE);
1141
1142 // check if suspending self
1143 self = (task == m_task_now);
1144 }
1145 }
1146
1147 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1148 if (self)
1149 {
1150 m_task_now->BusyWaitWhileSleeping();
1151 }
1152 }
1153
1157 void ResumeTask(ITask *user_task) override
1158 {
1159 STK_ASSERT(user_task != nullptr);
1160
1161 // avoid race with OnTick
1163
1164 KernelTask *const task = FindTaskByUserTask(user_task);
1165 STK_ASSERT(task != nullptr);
1166
1167 if (task->IsSleeping())
1168 {
1169 task->Wake();
1170 }
1171 }
1172
1178 {
1179 size_t count = 0U;
1180 const size_t limit = Min(tasks.GetSize(), TASKS_MAX);
1181
1182 // avoid race with OnTick
1184
1185 for (size_t i = 0U; i < limit; ++i)
1186 {
1187 KernelTask *const task = &m_task_storage[i];
1188 if (task->IsBusy())
1189 {
1190 tasks[count++] = task;
1191 }
1192 }
1193
1194 return count;
1195 }
1196
1201 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1202 {
1203 size_t count = 0U;
1204 const size_t limit = Min(user_tasks.GetSize(), TASKS_MAX);
1205
1206 // avoid race with OnTick
1208
1209 for (size_t i = 0U; i < limit; ++i)
1210 {
1211 KernelTask *const task = &m_task_storage[i];
1212 if (task->IsBusy())
1213 {
1214 user_tasks[count++] = task->GetUserTask();
1215 }
1216 }
1217
1218 return count;
1219 }
1220
1230 {
1232
1233 // stacks of the traps must be re-initilized on every subsequent Start
1234 InitTraps();
1235
1236 // start tracing
1237 #if STK_SEGGER_SYSVIEW
1238 SEGGER_SYSVIEW_Start();
1239 for (size_t i = 0U; i < TASKS_MAX; ++i)
1240 {
1241 KernelTask *task = &m_task_storage[i];
1242 if (task->IsBusy())
1243 {
1244 SendTaskTraceInfo(task);
1245 }
1246 }
1247 #endif
1248
1249 m_platform.Start();
1250 }
1251
1256 bool IsStarted() const
1257 {
1258 return (m_task_now != nullptr);
1259 }
1260
1264 IPlatform *GetPlatform() override { return &m_platform; }
1265
1270
1273 EKernelState GetState() const override { return m_kstate; }
1274
1275protected:
1289
1302
1309 static constexpr Timeout YIELD_TICKS = 2;
1310
1314 {
1315 return (state > FSM_STATE_NONE) &&
1316 (state < FSM_STATE_MAX);
1317 }
1318
1322 {
1323 // init stack for a Sleep trap
1324 {
1325 SleepTrapStack &sleep = m_sleep_trap[0];
1326
1327 SleepTrapStackMemory wrapper(&sleep.memory);
1328 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1329 #if STK_NEED_TASK_ID
1330 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1331 #endif
1332
1333 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1334 }
1335
1336 // init stack for an Exit trap
1338 {
1339 ExitTrapStack &exit = m_exit_trap[0];
1340
1341 ExitTrapStackMemory wrapper(&exit.memory);
1342 exit.stack.access_mode = ACCESS_PRIVILEGED;
1343 #if STK_NEED_TASK_ID
1344 exit.stack.tid = SYS_TASK_ID_EXIT;
1345 #endif
1346
1347 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1348 }
1349 }
1350
1355 KernelTask *AllocateNewTask(ITask *user_task)
1356 {
1357 // look for a free kernel task
1358 KernelTask *new_task = nullptr;
1359 for (size_t i = 0U; i < TASKS_MAX; ++i)
1360 {
1361 KernelTask *const task = &m_task_storage[i];
1362 if (task->IsBusy())
1363 {
1364 // avoid task collision
1365 STK_ASSERT(task->m_user != user_task);
1366
1367 // avoid stack collision
1368 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1369 }
1370 else
1371 if (new_task == nullptr)
1372 {
1373 new_task = task;
1374 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1375 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1376 #endif
1377 }
1378 else
1379 {
1380 // noop, continue to the next slot
1381 }
1382 }
1383
1384 // if nullptr - exceeded max supported kernel task count, application design failure
1385 STK_ASSERT(new_task != nullptr);
1386
1387 new_task->Bind(&m_platform, user_task);
1388
1389 return new_task;
1390 }
1391
1395 void AddKernelTask(KernelTask *task)
1396 {
1397 #if STK_SEGGER_SYSVIEW
1398 // start tracing new task
1399 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1400 if (IsStarted())
1401 SendTaskTraceInfo(task);
1402 #endif
1403
1404 m_strategy.AddTask(task);
1405 }
1406
1411 {
1412 KernelTask *const task = AllocateNewTask(user_task);
1413 STK_ASSERT(task != nullptr);
1414
1415 AddKernelTask(task);
1416 }
1417
1425 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1426 {
1427 KernelTask *const task = AllocateNewTask(user_task);
1428 STK_ASSERT(task != nullptr);
1429
1430 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1431
1432 AddKernelTask(task);
1433 }
1434
1440 {
1441 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1442 STK_ASSERT(caller != nullptr);
1443
1444 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1445 caller->m_srt[0].add_task_req = &req;
1446
1447 // notify kernel
1449
1450 // switch out and wait for completion (due to context switch request could be processed here)
1451 if (caller->m_srt[0].add_task_req != nullptr)
1452 {
1453 m_service.SwitchToNext();
1454 }
1455
1456 STK_ASSERT(caller->m_srt[0].add_task_req == nullptr);
1457 }
1458
1463 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
1464 {
1465 KernelTask *found_task = nullptr;
1466
1467 for (size_t i = 0U; i < TASKS_MAX; ++i)
1468 {
1469 KernelTask *const task = &m_task_storage[i];
1470 if (task->GetUserTask() == user_task)
1471 {
1472 found_task = task;
1473 break;
1474 }
1475 }
1476
1477 return found_task;
1478 }
1479
1484 KernelTask *FindTaskByStack(const Stack *stack)
1485 {
1486 KernelTask *found_task = nullptr;
1487
1488 for (size_t i = 0U; i < TASKS_MAX; ++i)
1489 {
1490 KernelTask *const task = &m_task_storage[i];
1491 if (task->GetUserStackPtr() == stack)
1492 {
1493 found_task = task;
1494 break;
1495 }
1496 }
1497
1498 return found_task;
1499 }
1500
1506 {
1507 STK_ASSERT(m_task_now != nullptr);
1508
1509 KernelTask *found_task = nullptr;
1510
1511 if (m_task_now->IsMemoryOfSP(SP))
1512 {
1513 found_task = m_task_now;
1514 }
1515 else
1516 {
1517 for (size_t i = 0U; i < TASKS_MAX; ++i)
1518 {
1519 KernelTask *const task = &m_task_storage[i];
1520
1521 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
1523 {
1524 if (!task->IsBusy())
1525 {
1526 continue;
1527 }
1528 }
1529
1530 if (task->IsMemoryOfSP(SP))
1531 {
1532 found_task = task;
1533 break;
1534 }
1535 }
1536 }
1537
1538 return found_task;
1539 }
1540
1545 void RemoveTask(KernelTask *task)
1546 {
1547 STK_ASSERT(task != nullptr);
1548
1549 #if STK_SEGGER_SYSVIEW
1550 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
1551 #endif
1552
1553 // notify task about pending exit
1554 task->GetUserTask()->OnExit();
1555
1556 m_strategy.RemoveTask(task);
1557 task->Unbind();
1558 }
1559
1570 __stk_attr_noinline void OnStart(Stack *&active) override
1571 {
1572 STK_ASSERT(m_strategy.GetSize() != 0);
1573
1574 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
1575 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1576 {
1577 for (size_t i = 0U; i < TASKS_MAX; ++i)
1578 {
1579 KernelTask *const task = &m_task_storage[i];
1580
1581 if (task->IsSleeping())
1582 {
1583 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1584 {
1585 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1586
1587 // notify strategy that task is sleeping
1588 m_strategy.OnTaskSleep(task);
1589 }
1590 }
1591 }
1592 }
1593
1594 // get initial state and first task
1595 {
1597
1598 KernelTask *next = nullptr;
1600
1601 // expecting only SLEEPING or SWITCHING states
1603
1605 {
1606 m_task_now = next;
1607 active = next->GetUserStackPtr();
1608
1610 {
1611 next->HrtOnSwitchedIn();
1612 }
1613 }
1614 else
1616 {
1618 active = &m_sleep_trap[0].stack;
1619 }
1620 else
1621 {
1622 // unexpected state
1624 }
1625 }
1626
1627 // is in running state
1629
1630 #if STK_SEGGER_SYSVIEW
1631 SEGGER_SYSVIEW_OnTaskStartExec(m_task_now->tid);
1632 #endif
1633 }
1634
1641 {
1643 {
1645
1646 // is in stopped state, i.e. is ready to Start() again
1648 }
1649 }
1650
1667 bool OnTick(Stack *&idle, Stack *&active
1668 #if STK_TICKLESS_IDLE
1669 , Timeout &ticks
1670 #endif
1671 ) override
1672 {
1673 #if !STK_TICKLESS_IDLE
1674 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
1675 enum { ticks = 1 };
1676 #endif
1677
1678 // advance internal timestamp
1679 m_service.IncrementTicks(ticks);
1680
1681 // consume elapsed and update to ticks to sleep
1682 #if STK_TICKLESS_IDLE
1683 ticks = (
1684 #else
1685 // notify compiler that we ignore a return value of UpdateTasks
1686 STK_UNUSED(
1687 #endif
1688 UpdateTasks(ticks));
1689
1690 // decide on a context switch
1691 return UpdateFsmState(idle, active);
1692 }
1693
1694 void OnTaskSwitch(Word caller_SP) override
1695 {
1696 OnTaskSleep(caller_SP, YIELD_TICKS);
1697 }
1698
1699 void OnTaskSleep(Word caller_SP, Timeout ticks) override
1700 {
1701 KernelTask *const task = FindTaskBySP(caller_SP);
1702 STK_ASSERT(task != nullptr);
1703
1704 // make change to HRT state and sleep time atomic
1705 {
1707
1709 {
1710 task->HrtOnWorkCompleted();
1711 }
1712
1713 if (ticks > 0)
1714 {
1715 task->ScheduleSleep(ticks);
1716 }
1717 }
1718
1719 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1720 task->BusyWaitWhileSleeping();
1721 }
1722
1723 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
1724 {
1725 KernelTask *const task = FindTaskBySP(caller_SP);
1726 STK_ASSERT(task != nullptr);
1727
1728 bool result = true;
1729
1730 // make change to HRT state and sleep time atomic
1731 {
1733
1734 // calculate signed delta (handles wrap-around correctly)
1735 const Ticks delta = timestamp - m_service.m_ticks;
1736
1737 if (delta > 0)
1738 {
1739 const Ticks infinite_ticks = WAIT_INFINITE;
1740 task->ScheduleSleep(static_cast<Timeout>(Min(delta, infinite_ticks)));
1741 }
1742 else
1743 {
1744 result = false; // deadline already hit or passed
1745 }
1746 }
1747
1748 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1749 task->BusyWaitWhileSleeping();
1750 return result;
1751 }
1752
1754 {
1755 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(task_id));
1756 if (task != nullptr)
1757 {
1759
1760 if (task->IsSleeping())
1761 {
1762 task->Wake();
1763 }
1764 }
1765 }
1766
1767 void OnTaskExit(Stack *stack) override
1768 {
1770 {
1771 KernelTask *const task = FindTaskByStack(stack);
1772 STK_ASSERT(task != nullptr);
1773
1774 // notify kernel to execute removal
1775 task->ScheduleRemoval();
1776 }
1777 else
1778 {
1779 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
1781 }
1782 }
1783
1784 IWaitObject *OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
1785 {
1787 {
1788 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
1789 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
1790 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
1791 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
1792
1793 KernelTask *const task = FindTaskBySP(caller_SP);
1794 STK_ASSERT(task != nullptr);
1795
1796 // configure waiting
1797 task->m_wait_obj->SetupWait(sync_obj, timeout);
1798
1799 // register ISyncObject if not yet
1800 if (sync_obj->GetHead() == nullptr)
1801 {
1802 m_sync_list->LinkBack(sync_obj);
1803 }
1804
1805 // start sleeping infinitely, we rely on a Wake call via WaitObject
1806 task->ScheduleSleep(WAIT_INFINITE);
1807
1808 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
1809 mutex->Unlock();
1810
1811 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1812 task->BusyWaitWhileSleeping();
1813
1814 // re-lock mutex when returning to the task's execution space
1815 mutex->Lock();
1816
1817 return task->m_wait_obj;
1818 }
1819 else
1820 {
1821 STK_ASSERT(false);
1822 return nullptr;
1823 }
1824 }
1825
1826 TId OnGetTid(Word caller_SP) override
1827 {
1828 KernelTask *const task = FindTaskBySP(caller_SP);
1829 STK_ASSERT(task != nullptr);
1830
1831 return task->GetTid();
1832 }
1833
1834 void OnSuspend(bool suspended) override
1835 {
1836 // toggle kernel state
1837 if (suspended)
1838 {
1839 if (m_kstate == KSTATE_RUNNING)
1840 {
1842 }
1843 }
1844 else
1845 {
1846 if (m_kstate == KSTATE_SUSPENDED)
1847 {
1849 }
1850 }
1851
1852 // force yield for a currently active task
1853 if (!m_task_now->IsSleeping())
1854 {
1855 m_task_now->ScheduleSleep(YIELD_TICKS);
1856 }
1857 }
1858
1859 void OnInheritWeight(TId tid, Weight weight)
1860 {
1861 STK_ASSERT(tid != TID_NONE);
1862 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1863
1864 if (weight != NO_WEIGHT)
1865 {
1866 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1867 STK_ASSERT(task != nullptr);
1868
1869 const Weight prev_weight = task->GetWeight();
1870
1871 if (prev_weight < weight)
1872 {
1873 task->SetCurrentWeight(weight);
1874 m_strategy.OnTaskWeightChange(task, prev_weight);
1875 }
1876 }
1877 }
1878
1880 {
1881 STK_ASSERT(tid != TID_NONE);
1882 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1883
1884 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1885 STK_ASSERT(task != nullptr);
1886
1887 const Weight prev_weight = task->GetWeight();
1888
1889 // restore to original or boost from wait objects
1890 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
1891
1892 m_strategy.OnTaskWeightChange(task, prev_weight);
1893 }
1894
1897 Timeout UpdateTasks(const Timeout elapsed_ticks)
1898 {
1899 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
1901 {
1902 UpdateSyncObjects(elapsed_ticks);
1903 }
1904
1905 if (m_request != REQ_NONE)
1906 {
1908 }
1909
1910 return UpdateTaskState(elapsed_ticks);
1911 }
1912
1922 Timeout UpdateTaskState(const Timeout elapsed_ticks)
1923 {
1925
1926 for (size_t i = 0U; i < TASKS_MAX; ++i)
1927 {
1928 KernelTask *const task = &m_task_storage[i];
1929
1930 if (task->IsSleeping())
1931 {
1933 {
1934 // task is pending removal, wait until it is switched out
1935 if (task->IsPendingRemoval())
1936 {
1937 const size_t tasks_left = m_strategy.GetSize();
1938
1939 if ((task != m_task_now) ||
1940 ((tasks_left == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
1941 {
1942 RemoveTask(task);
1943 continue;
1944 }
1945 }
1946 }
1947
1948 // deliver sleep event to strategy
1949 // note: only currently scheduled task can be pending to sleep
1950 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1951 {
1952 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1953 {
1954 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1955
1956 // notify strategy that task is sleeping
1957 m_strategy.OnTaskSleep(task);
1958 }
1959 }
1960
1961 // advance sleep time by a tick
1962 task->m_time_sleep += elapsed_ticks;
1963
1964 // deliver sleep event to strategy
1965 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1966 {
1967 // notify strategy that task woke up
1968 if (!task->IsSleeping())
1969 {
1970 m_strategy.OnTaskWake(task);
1971 }
1972 }
1973 }
1974 else
1975 {
1977 {
1978 // in HRT mode we trace how long task spent in active state (doing some work)
1979 if (task->IsBusy())
1980 {
1981 task->m_hrt[0].duration += elapsed_ticks;
1982
1983 // check if deadline is missed (HRT failure)
1984 if (task->HrtIsDeadlineMissed(task->m_hrt[0].duration))
1985 {
1986 // report deadline overrun to a strategy which supports overrun recovery
1987 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
1988 {
1989 if (!m_strategy.OnTaskDeadlineMissed(task))
1990 {
1991 // report failure if it could not be recovered by the scheduling strategy
1992 task->HrtHardFailDeadline(&m_platform);
1993 }
1994 }
1995 else
1996 {
1997 task->HrtHardFailDeadline(&m_platform);
1998 }
1999 }
2000 }
2001 }
2002 }
2003
2004 // get the number ticks the driver has to keep CPU in Idle
2006 {
2007 if ((sleep_ticks > 1) && task->IsBusy())
2008 {
2009 sleep_ticks = task->GetSleepTicks(sleep_ticks);
2010 }
2011 }
2012 }
2013
2014 return sleep_ticks;
2015 }
2016
2019 void UpdateSyncObjects(const Timeout elapsed_ticks)
2020 {
2021 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
2022
2023 while (itr != nullptr)
2024 {
2025 ISyncObject::ListEntryType *const next = itr->GetNext();
2026
2027 if (!util::DListCast::ListEntryToParent<ISyncObject>(itr)->Tick(elapsed_ticks))
2028 {
2029 m_sync_list->Unlink(itr);
2030 }
2031
2032 itr = next;
2033 }
2034 }
2035
2039 {
2040 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2041 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2043 {
2044 // process serialized AddTask request made from another active task, requesting process
2045 // is currently waiting due to SwitchToNext()
2046 if ((m_request & REQ_ADD_TASK) != 0U)
2047 {
2049
2050 for (size_t i = 0U; i < TASKS_MAX; ++i)
2051 {
2052 KernelTask *const task = &m_task_storage[i];
2053
2054 if (task->m_srt[0].add_task_req != nullptr)
2055 {
2056 AllocateAndAddNewTask(task->m_srt[0].add_task_req->user_task);
2057
2058 task->m_srt[0].add_task_req = nullptr;
2059 __stk_full_memfence();
2060 }
2061 }
2062 }
2063 }
2064 }
2065
2070 EFsmEvent FetchNextEvent(KernelTask *&next)
2071 {
2073
2074 // try getting next task for scheduling
2076
2077 // sleep-aware strategy returns nullptr if no active tasks available
2078 if (next != nullptr)
2079 {
2080 // strategy must provide active-only task
2081 STK_ASSERT(!next->IsSleeping());
2082
2083 // if was sleeping, process wake event first
2085 }
2086 // start sleeping
2087 else
2088 {
2090 {
2091 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2092 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2093 if (m_strategy.GetSize() == 0U)
2094 {
2095 next = nullptr;
2096 type = FSM_EVENT_EXIT;
2097 }
2098 }
2099 }
2100
2101 return type;
2102 }
2103
2108#ifdef _STK_UNDER_TEST
2109 virtual
2110#endif
2111 EFsmState GetNewFsmState(KernelTask *&next)
2112 {
2114 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2115 }
2116
2122 bool UpdateFsmState(Stack *&idle, Stack *&active)
2123 {
2124 KernelTask *const now = m_task_now, *next = nullptr;
2125 bool switch_context = false;
2126
2127 const EFsmState new_state = GetNewFsmState(next);
2128
2129 switch (new_state)
2130 {
2132 switch_context = StateSwitch(now, next, idle, active);
2133 m_fsm_state = new_state;
2134 break;
2135 case FSM_STATE_SLEEPING:
2136 switch_context = StateSleep(now, next, idle, active);
2137 m_fsm_state = new_state;
2138 break;
2139 case FSM_STATE_WAKING:
2140 switch_context = StateWake(now, next, idle, active);
2141 m_fsm_state = new_state;
2142 break;
2143 case FSM_STATE_EXITING:
2144 switch_context = StateExit(now, next, idle, active);
2145 m_fsm_state = new_state;
2146 break;
2147 case FSM_STATE_NONE:
2148 break; // valid intermittent non-persisting state: no-transition
2149 case FSM_STATE_MAX:
2150 default: // invalid state value
2152 break;
2153 }
2154
2155 return switch_context;
2156 }
2157
2165 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2166 {
2167 STK_ASSERT(now != nullptr);
2168 STK_ASSERT(next != nullptr);
2169
2170 bool switch_context = false;
2171
2172 // if equal: do not switch context because task did not change
2173 if (next != now)
2174 {
2175 idle = now->GetUserStackPtr();
2176 active = next->GetUserStackPtr();
2177
2178 // if stack memory is exceeded these assertions will be hit
2179 if (now->IsBusy())
2180 {
2181 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2182 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2183 }
2184 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2185
2186 m_task_now = next;
2187
2189 {
2190 if (now->m_hrt[0].done)
2191 {
2192 now->HrtOnSwitchedOut();
2193 next->HrtOnSwitchedIn();
2194 }
2195 }
2196
2197 #if STK_SEGGER_SYSVIEW
2198 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SWITCH);
2199 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2200 #endif
2201
2202 switch_context = true;
2203 }
2204
2205 return switch_context;
2206 }
2207
2215 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2216 {
2217 STK_UNUSED(now);
2218
2219 STK_ASSERT(next != nullptr);
2220
2221 idle = &m_sleep_trap[0].stack;
2222 active = next->GetUserStackPtr();
2223
2224 // if stack memory is exceeded these assertions will be hit
2226 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2227
2228 m_task_now = next;
2229
2230 #if STK_SEGGER_SYSVIEW
2231 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2232 #endif
2233
2235 {
2236 next->HrtOnSwitchedIn();
2237 }
2238
2239 return true; // switch context
2240 }
2241
2249 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2250 {
2251 STK_UNUSED(next);
2252
2253 STK_ASSERT(now != nullptr);
2254 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
2255
2256 idle = now->GetUserStackPtr();
2257 active = &m_sleep_trap[0].stack;
2258
2260
2261 #if STK_SEGGER_SYSVIEW
2262 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2263 #endif
2264
2266 {
2267 if (!now->IsPendingRemoval())
2268 {
2269 now->HrtOnSwitchedOut();
2270 }
2271 }
2272
2273 return true; // switch context
2274 }
2275
2284 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2285 {
2286 STK_UNUSED(now);
2287 STK_UNUSED(next);
2288
2290 {
2291 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
2292 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
2293
2294 idle = nullptr;
2295 active = &m_exit_trap[0].stack;
2296
2297 m_task_now = nullptr;
2298
2299 m_platform.Stop();
2300 }
2301 else
2302 {
2303 STK_UNUSED(idle);
2304 STK_UNUSED(active);
2305 }
2306
2307 return false;
2308 }
2309
2313 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
2314
2320 {
2323 }
2324
2325#if STK_SEGGER_SYSVIEW
2330 void SendTaskTraceInfo(KernelTask *task)
2331 {
2332 STK_ASSERT(task->IsBusy());
2333
2334 SEGGER_SYSVIEW_TASKINFO info =
2335 {
2336 .TaskID = task->GetUserStackPtr()->tid,
2337 .sName = task->GetUserTask()->GetTraceName(),
2338 .Prio = 0,
2339 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
2340 .StackSize = task->GetUserTask()->GetStackSizeBytes()
2341 };
2342 SEGGER_SYSVIEW_SendTaskInfo(&info);
2343 }
2344#endif
2345
2346 // Kernel modes:
2347 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
2348 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
2349 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
2350 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
2351 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
2352
2353 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
2355
2356 // If hit here: Kernel mode must be assigned.
2357 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
2358
2359 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
2360 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
2361 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
2362
2363 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
2364 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
2365 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
2366
2367 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
2368 // which destroys the precise periodicity HRT depends on.
2369 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
2370 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
2371
2372 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
2373 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
2374 !TStrategy::PRIORITY_INHERITANCE_API);
2375
2380
2395
2411
2418
2419 KernelService m_service;
2420 TPlatform m_platform;
2421 TStrategy m_strategy;
2422 KernelTask *m_task_now;
2424 SleepTrapStack m_sleep_trap[1];
2427 volatile uint8_t m_request;
2430
2432 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
2437 };
2438
2440};
2441
2442} // namespace stk
2443
2444#endif /* STK_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:438
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:175
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:255
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:382
#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:429
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
Definition stk_defs.h:456
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
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
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:34
static constexpr ITask * GetUserTaskFromTid(TId task_id) noexcept
Get task instance from its identifier.
Definition stk_arch.h:526
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:625
@ 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
constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:199
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()
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
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:619
static constexpr TId GetTidFromUserTask(const ITask *task) noexcept
Get task identifier from ITask instance.
Definition stk_arch.h:520
uint64_t Cycles
Cycles value.
Definition stk_common.h:140
Word TId
Task (thread) id.
Definition stk_common.h:120
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:145
@ 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.
static __stk_forceinline void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:444
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:106
static __stk_forceinline T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:379
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
void OnStop() override
Called by the platform driver after a scheduler stop (all tasks have exited).
Definition stk.h:1640
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2122
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1355
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1439
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:1767
void OnTaskSleepCancel(TId task_id)
Definition stk.h:1753
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1281
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:1484
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:2379
~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:1667
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:1834
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1092
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2111
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel before Start().
Definition stk.h:1067
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:1879
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:1570
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:2215
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:1505
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1321
static constexpr bool IsHrtMode()
Definition stk.h:2349
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:1003
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:2417
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1295
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:1177
static constexpr bool IsSyncMode()
Definition stk.h:2350
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance.
Definition stk.h:1463
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1313
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:1859
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1157
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:1699
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1229
static constexpr bool IsTicklessMode()
Definition stk.h:2351
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:1545
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1395
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1273
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:1784
bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Exits from scheduling.
Definition stk.h:2284
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1264
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1410
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:1694
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:966
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:1425
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:1826
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1201
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:1897
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:2319
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:2313
static constexpr bool IsDynamicMode()
Definition stk.h:2348
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1269
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2165
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:1042
Kernel()
Construct the kernel with all storage zero-initialized and the request flag set to ~0 (indicating uni...
Definition stk.h:933
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2038
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:2249
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, advance sleep timers, and track HRT durations.
Definition stk.h:1922
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:2019
static constexpr bool IsStaticMode()
Definition stk.h:2347
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1256
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:1723
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1120
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2070
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:252
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:706
Timeout GetSleepTicks(Timeout sleep_ticks)
Definition stk.h:337
TId GetTid() const
Get task identifier.
Definition stk.h:185
void HrtOnSwitchedOut()
Called when task is switched out from the scheduling process.
Definition stk.h:649
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:272
friend class Kernel
Definition stk.h:122
bool HrtIsDeadlineMissed(Timeout duration) const
Check if deadline missed.
Definition stk.h:692
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:742
void ScheduleRemoval()
Schedule the removal of the task from the kernel on next tick.
Definition stk.h:588
Stack m_stack
Stack descriptor (SP register value + access mode + optional tid).
Definition stk.h:739
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:537
~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:744
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:669
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:624
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:740
void BusyWaitWhileSleeping() const
Block further execution of the task's context while in sleeping state.
Definition stk.h:725
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:738
Timeout GetHrtRelativeDeadline() const override
Get remaining HRT deadline (ticks left before the deadline expires).
Definition stk.h:318
void SetCurrentWeight(Weight weight) override
Update the run-time scheduling weight (weighted strategies only).
Definition stk.h:202
Stack GetUserStack() const override
Get stack descriptor for this task slot.
Definition stk.h:170
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:736
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:743
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:683
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:741
bool IsPendingRemoval() const
Check if task is pending removal.
Definition stk.h:605
Timeout GetHrtDeadline() const override
Get absolute HRT deadline (ticks elapsed since task was activated).
Definition stk.h:295
void Unbind()
Reset this slot to the free (unbound) state, clearing all scheduling metadata.
Definition stk.h:563
void HrtOnSwitchedIn()
Called when task is switched into the scheduling process.
Definition stk.h:644
bool IsMemoryOfSP(Word SP) const
Check if Stack Pointer (SP) belongs to this task.
Definition stk.h:610
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:745
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:382
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:388
AddTaskRequest * add_task_req
Definition stk.h:398
Per-task Hard Real-Time (HRT) scheduling metadata.
Definition stk.h:406
void Clear()
Clear all fields, ready for slot re-use or re-activation.
Definition stk.h:412
volatile bool done
Set to true when the task signals work completion (via Yield() or on exit). Triggers HrtOnSwitchedOut...
Definition stk.h:423
Timeout deadline
Maximum allowed active duration in ticks (relative to switch-in). Exceeding this triggers OnDeadlineM...
Definition stk.h:421
Timeout periodicity
Activation period in ticks: the task is re-activated every this many ticks.
Definition stk.h:420
Timeout duration
Ticks spent in the active (non-sleeping) state in the current period. Incremented by UpdateTaskState(...
Definition stk.h:422
Concrete implementation of IWaitObject, embedded in each KernelTask slot.
Definition stk.h:433
bool IsWaiting() const
Check if busy with waiting.
Definition stk.h:465
Timeout m_time_wait
Ticks remaining until timeout. Decremented each tick; WAIT_INFINITE means no timeout.
Definition stk.h:530
void Wake(bool timeout) override
Wake the waiting task (called by ISyncObject when it signals).
Definition stk.h:472
~WaitObject()=default
Destructor.
bool Tick(Timeout elapsed_ticks) override
Advance the timeout countdown by one tick.
Definition stk.h:491
bool IsTimeout() const override
Check whether the wait expired due to timeout.
Definition stk.h:460
void SetupWait(ISyncObject *sync_obj, Timeout timeout)
Configure and arm this wait object for a new wait operation.
Definition stk.h:516
TId GetTid() const override
Get the TId of the task that owns this wait object.
Definition stk.h:455
volatile bool m_timeout
true if the wait expired due to timeout rather than a Wake() signal.
Definition stk.h:529
ISyncObject * m_sync_obj
Sync object this wait is registered with, or NULL when not waiting.
Definition stk.h:528
KernelTask * m_task
Back-pointer to the owning KernelTask. Set once at construction; never changes.
Definition stk.h:527
Payload stored in the sync object's kernel-side list entry while a task is waiting.
Definition stk.h:448
ISyncObject * sync_obj
Sync object whose Tick() will be called each kernel tick.
Definition stk.h:449
KernelService()
Construct an uninitialized service instance (m_platform = null, m_ticks = 0).
Definition stk.h:890
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:845
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:825
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:918
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:768
friend class Kernel
Definition stk.h:757
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:785
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:917
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:762
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:817
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:858
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:801
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:878
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:870
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:766
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:764
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:770
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:760
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:911
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:832
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:903
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2389
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:2390
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:2393
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2392
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2405
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:2409
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:2406
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2408
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:250
Stack descriptor.
Definition stk_common.h:281
EAccessMode access_mode
Hardware access mode of the owning task (see EAccessMode).
Definition stk_common.h:283
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Wait object.
Definition stk_common.h:345
Synchronization object.
Definition stk_common.h:439
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:451
virtual void AddWaitObject(IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:457
DLHeadType ListHeadType
List head type for ISyncObject elements.
Definition stk_common.h:446
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:542
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:599
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:638
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:671
Interface for a platform driver.
Definition stk_common.h:763
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
Definition stk_common.h:771
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:568
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.
static __stk_forceinline TTargetType * ListEntryToParent(TSourceType *const lentry)
Safely casts an intrusive list entry to its concrete parent container object type.