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 bool is_match = false;
613
614 const Word start = hw::PtrToWord(m_user->GetStack());
615 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
616
617 if ((SP >= start) && (SP <= end))
618 {
619 is_match = true;
620 }
621 #if STK_TZ_SECURE // lookup Secure memory region too when on a Secure side
622 else
623 {
624 IStackMemory *const secure_mem = m_user->GetSecureStackMemory();
625
626 if (secure_mem != nullptr)
627 {
628 const Word s_start = hw::PtrToWord(secure_mem->GetStack());
629 const Word s_end = s_start + (secure_mem->GetStackSize() * sizeof(Word));
630
631 if ((SP >= s_start) && (SP <= s_end))
632 {
633 is_match = true;
634 }
635 }
636 }
637 #endif
638
639 return is_match;
640 }
641
648 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
649 {
650 STK_ASSERT(periodicity_tc > 0);
651 STK_ASSERT(deadline_tc > 0);
652 STK_ASSERT(start_delay_tc >= 0);
653 STK_ASSERT(periodicity_tc < INT32_MAX);
654 STK_ASSERT(deadline_tc < INT32_MAX);
655
656 m_hrt[0].periodicity = periodicity_tc;
657 m_hrt[0].deadline = deadline_tc;
658
659 if (start_delay_tc > 0)
660 {
661 ScheduleSleep(start_delay_tc);
662 }
663 }
664
669
674 {
675 const Timeout duration = m_hrt[0].duration;
676
677 STK_ASSERT(duration >= 0);
678
679 const Timeout sleep = m_hrt[0].periodicity - duration;
680 if (sleep > 0)
681 {
682 ScheduleSleep(sleep);
683 }
684
685 m_hrt[0].duration = 0;
686 m_hrt[0].done = false;
687 }
688
694 {
695 const Timeout duration = m_hrt[0].duration;
696
697 STK_ASSERT(duration >= 0);
699
700 m_user->OnDeadlineMissed(duration);
701 platform->ProcessHardFault();
702 }
703
708 {
709 m_hrt[0].done = true;
710 __stk_full_memfence();
711 }
712
716 bool HrtIsDeadlineMissed(Timeout duration) const
717 {
718 return (duration > m_hrt[0].deadline);
719 }
720
731 {
732 STK_ASSERT(ticks > 0);
733
734 // set state first as kernel checks it when task IsSleeping
735 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
736 {
737 if (!IsSleeping())
738 {
740 }
741 }
742
743 m_time_sleep = -ticks;
744 __stk_full_memfence();
745 }
746
750 {
751 while (IsSleeping())
752 {
753 __stk_relax_cpu();
754 }
755 }
756
761
764 volatile uint32_t m_state;
770 };
771
779 class KernelService final : public IKernelService
780 {
781 friend class Kernel;
782
783 public:
784 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
785
786 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
787
788 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
789
790 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
791
792 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
793
794 void Delay(Timeout ticks) override
795 {
797 STK_ASSERT(ticks >= 0);
798
799 Ticks now = GetTicks();
800 const Ticks deadline = now + ticks;
801 STK_ASSERT(deadline >= now);
802
803 for (; now < deadline; now = GetTicks())
804 {
805 __stk_relax_cpu();
806 }
807 }
808
809 void Sleep(Timeout ticks) override
810 {
812 STK_ASSERT(ticks >= 0);
813
815 {
816 m_kernel->m_platform.Sleep(ticks);
817 }
818 else
819 {
820 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
821 STK_ASSERT(false);
822 }
823 }
824
825 bool SleepUntil(Ticks timestamp) override
826 {
828
830 {
831 return m_kernel->m_platform.SleepUntil(timestamp);
832 }
833 else
834 {
835 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
836 STK_ASSERT(false);
837 return false;
838 }
839 }
840
841 void SleepCancel(TId task_id) override
842 {
844 {
845 m_kernel->OnTaskSleepCancel(task_id);
846 }
847 }
848
849 void SwitchToNext() override
850 {
852
853 m_kernel->m_platform.SwitchToNext();
854 }
855
856 EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
857 {
859 {
860 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
861 }
862 else
863 {
864 STK_ASSERT(false);
865 return WAIT_RESULT_FAIL;
866 }
867 }
868
869 Timeout Suspend() override
870 {
872 {
873 return m_kernel->m_platform.Suspend();
874 }
875 else
876 {
877 STK_ASSERT(false);
878 return 0;
879 }
880 }
881
882 void Resume(Timeout elapsed_ticks) override
883 {
885 {
886 return m_kernel->m_platform.Resume(elapsed_ticks);
887 }
888 else
889 {
890 STK_ASSERT(false);
891 }
892 }
893
894 void InheritWeight(TId tid, Weight weight) override
895 {
896 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
897 {
898 m_kernel->OnInheritWeight(tid, weight);
899 }
900 }
901
902 void RestoreWeight(TId tid, ISyncObject *sobj) override
903 {
904 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
905 {
906 m_kernel->OnRestoreWeight(tid, sobj);
907 }
908 }
909
910 private:
914 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
915 {}
916
921
927 void Initialize(Kernel *kernel)
928 {
929 m_kernel = kernel;
930 }
931
935 void IncrementTicks(Ticks advance)
936 {
937 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
939 }
940
942 volatile Ticks m_ticks;
943 };
944
945public:
948 static constexpr size_t TASKS_MAX = TSize;
949
959 {
960 #ifdef _DEBUG
961 // TPlatform must inherit IPlatform
962 IPlatform *platform = &m_platform;
963 STK_UNUSED(platform);
964
965 // TStrategy must inherit ITaskSwitchStrategy
966 ITaskSwitchStrategy *strategy = &m_strategy;
967 STK_UNUSED(strategy);
968 #endif
969
970 #if !STK_TICKLESS_IDLE
971 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
972 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
973 #endif
974 }
975
980
990 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
991 {
992 STK_ASSERT(resolution_us != 0);
993 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
995
996 // reinitialize key state variables
997 m_task_now = nullptr;
1000
1001 // exit trap is required only for KERNEL_DYNAMIC mode
1002 Stack *exit_trap;
1004 {
1005 exit_trap = &m_exit_trap[0].stack;
1006 }
1007 else
1008 {
1009 exit_trap = nullptr;
1010 }
1011
1012 m_service.Initialize(this);
1013 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
1014
1015 // now ready to Start()
1017 }
1018
1027 __stk_attr_noinline void AddTask(ITask *user_task) override
1028 {
1030 {
1031 STK_ASSERT(user_task != nullptr);
1033
1034 // when started the operation must be serialized by switching out from processing until
1035 // kernel processes this request
1036 if (IsStarted())
1037 {
1039 {
1040 RequestAddTask(user_task);
1041 }
1042 else
1043 {
1044 STK_ASSERT(false);
1045 }
1046 }
1047 else
1048 {
1049 AllocateAndAddNewTask(user_task);
1050 }
1051 }
1052 else
1053 {
1054 STK_ASSERT(false);
1055 }
1056 }
1057
1066 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1067 Timeout start_delay_tc) override
1068 {
1070 {
1071 STK_ASSERT(user_task != nullptr);
1074
1075 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1076 }
1077 else
1078 {
1079 STK_ASSERT(false);
1080 }
1081 }
1082
1091 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1092 {
1094 {
1095 STK_ASSERT(user_task != nullptr);
1097
1098 KernelTask *const task = FindTaskByUserTask(user_task);
1099 if (task != nullptr)
1100 {
1101 RemoveTask(task);
1102 }
1103 }
1104 else
1105 {
1106 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1107 STK_ASSERT(false);
1108 }
1109 }
1110
1117 {
1119 {
1120 STK_ASSERT(user_task != nullptr);
1122
1124
1125 KernelTask *const task = FindTaskByUserTask(user_task);
1126 if (task != nullptr)
1127 {
1128 task->ScheduleRemoval();
1129 }
1130 }
1131 else
1132 {
1133 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1134 STK_ASSERT(false);
1135 }
1136 }
1137
1144 void SuspendTask(ITask *user_task, bool &suspended) override
1145 {
1146 STK_ASSERT(user_task != nullptr);
1147
1148 bool self = false;
1149
1150 // avoid race with OnTick
1151 {
1153
1154 KernelTask *const task = FindTaskByUserTask(user_task);
1155 STK_ASSERT(task != nullptr);
1156
1157 // only suspend if the task is currently awake: if it is already sleeping
1158 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1159 // that would corrupt the original sleep state and, for sync-object waits,
1160 // would interfere with WaitObject::Tick()
1161 suspended = !task->IsSleeping();
1162 if (suspended == true)
1163 {
1164 task->ScheduleSleep(WAIT_INFINITE);
1165
1166 // check if suspending self
1167 self = (task == m_task_now);
1168 }
1169 }
1170
1171 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1172 if (self)
1173 {
1174 m_task_now->BusyWaitWhileSleeping();
1175 }
1176 }
1177
1181 void ResumeTask(ITask *user_task) override
1182 {
1183 STK_ASSERT(user_task != nullptr);
1184
1185 // avoid race with OnTick
1187
1188 KernelTask *const task = FindTaskByUserTask(user_task);
1189 STK_ASSERT(task != nullptr);
1190
1191 if (task->IsSleeping())
1192 {
1193 task->Wake();
1194 }
1195 }
1196
1202 {
1203 size_t count = 0U;
1204 const size_t limit = Min(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 tasks[count++] = task;
1215 }
1216 }
1217
1218 return count;
1219 }
1220
1225 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1226 {
1227 size_t count = 0U;
1228 const size_t limit = Min(user_tasks.GetSize(), TASKS_MAX);
1229
1230 // avoid race with OnTick
1232
1233 for (size_t i = 0U; i < limit; ++i)
1234 {
1235 KernelTask *const task = &m_task_storage[i];
1236 if (task->IsBusy())
1237 {
1238 user_tasks[count++] = task->GetUserTask();
1239 }
1240 }
1241
1242 return count;
1243 }
1244
1254 {
1256
1257 // stacks of the traps must be re-initilized on every subsequent Start
1258 InitTraps();
1259
1260 // start tracing
1261 #if STK_SEGGER_SYSVIEW
1262 SEGGER_SYSVIEW_Start();
1263 for (size_t i = 0U; i < TASKS_MAX; ++i)
1264 {
1265 KernelTask *task = &m_task_storage[i];
1266 if (task->IsBusy())
1267 {
1268 SendTaskTraceInfo(task);
1269 }
1270 }
1271 #endif
1272
1273 m_platform.Start();
1274 }
1275
1280 bool IsStarted() const
1281 {
1282 return (m_task_now != nullptr);
1283 }
1284
1288 IPlatform *GetPlatform() override { return &m_platform; }
1289
1294
1297 EKernelState GetState() const override { return m_kstate; }
1298
1299protected:
1313
1326
1333 static constexpr Timeout YIELD_TICKS = 2;
1334
1338 {
1339 return (state > FSM_STATE_NONE) &&
1340 (state < FSM_STATE_MAX);
1341 }
1342
1346 {
1347 // init stack for a Sleep trap
1348 {
1349 SleepTrapStack &sleep = m_sleep_trap[0];
1350
1351 SleepTrapStackMemory wrapper(&sleep.memory);
1352 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1353 #if STK_NEED_TASK_ID
1354 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1355 #endif
1356
1357 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1358 }
1359
1360 // init stack for an Exit trap
1362 {
1363 ExitTrapStack &exit = m_exit_trap[0];
1364
1365 ExitTrapStackMemory wrapper(&exit.memory);
1366 exit.stack.access_mode = ACCESS_PRIVILEGED;
1367 #if STK_NEED_TASK_ID
1368 exit.stack.tid = SYS_TASK_ID_EXIT;
1369 #endif
1370
1371 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1372 }
1373 }
1374
1379 KernelTask *AllocateNewTask(ITask *user_task)
1380 {
1381 // look for a free kernel task
1382 KernelTask *new_task = nullptr;
1383 for (size_t i = 0U; i < TASKS_MAX; ++i)
1384 {
1385 KernelTask *const task = &m_task_storage[i];
1386 if (task->IsBusy())
1387 {
1388 // avoid task collision
1389 STK_ASSERT(task->m_user != user_task);
1390
1391 // avoid stack collision
1392 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1393 }
1394 else
1395 if (new_task == nullptr)
1396 {
1397 new_task = task;
1398 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1399 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1400 #endif
1401 }
1402 else
1403 {
1404 // noop, continue to the next slot
1405 }
1406 }
1407
1408 // if nullptr - exceeded max supported kernel task count, application design failure
1409 STK_ASSERT(new_task != nullptr);
1410
1411 new_task->Bind(&m_platform, user_task);
1412
1413 return new_task;
1414 }
1415
1419 void AddKernelTask(KernelTask *task)
1420 {
1421 #if STK_SEGGER_SYSVIEW
1422 // start tracing new task
1423 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1424 if (IsStarted())
1425 SendTaskTraceInfo(task);
1426 #endif
1427
1428 m_strategy.AddTask(task);
1429 }
1430
1435 {
1436 KernelTask *const task = AllocateNewTask(user_task);
1437 STK_ASSERT(task != nullptr);
1438
1439 AddKernelTask(task);
1440 }
1441
1449 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1450 {
1451 KernelTask *const task = AllocateNewTask(user_task);
1452 STK_ASSERT(task != nullptr);
1453
1454 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1455
1456 AddKernelTask(task);
1457 }
1458
1464 {
1465 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1466 STK_ASSERT(caller != nullptr);
1467
1468 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1469 caller->m_srt[0].add_task_req = &req;
1470
1471 // notify kernel
1473
1474 // switch out and wait for completion (due to context switch request could be processed here)
1475 if (caller->m_srt[0].add_task_req != nullptr)
1476 {
1477 m_service.SwitchToNext();
1478 }
1479
1480 STK_ASSERT(caller->m_srt[0].add_task_req == nullptr);
1481 }
1482
1487 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
1488 {
1489 KernelTask *found_task = nullptr;
1490
1491 for (size_t i = 0U; i < TASKS_MAX; ++i)
1492 {
1493 KernelTask *const task = &m_task_storage[i];
1494 if (task->GetUserTask() == user_task)
1495 {
1496 found_task = task;
1497 break;
1498 }
1499 }
1500
1501 return found_task;
1502 }
1503
1508 KernelTask *FindTaskByStack(const Stack *stack)
1509 {
1510 KernelTask *found_task = nullptr;
1511
1512 for (size_t i = 0U; i < TASKS_MAX; ++i)
1513 {
1514 KernelTask *const task = &m_task_storage[i];
1515 if (task->GetUserStackPtr() == stack)
1516 {
1517 found_task = task;
1518 break;
1519 }
1520 }
1521
1522 return found_task;
1523 }
1524
1530 {
1531 STK_ASSERT(m_task_now != nullptr);
1532
1533 KernelTask *found_task = nullptr;
1534
1535 if (m_task_now->IsMemoryOfSP(SP))
1536 {
1537 found_task = m_task_now;
1538 }
1539 else
1540 {
1541 for (size_t i = 0U; i < TASKS_MAX; ++i)
1542 {
1543 KernelTask *const task = &m_task_storage[i];
1544
1545 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
1547 {
1548 if (!task->IsBusy())
1549 {
1550 continue;
1551 }
1552 }
1553
1554 if (task->IsMemoryOfSP(SP))
1555 {
1556 found_task = task;
1557 break;
1558 }
1559 }
1560 }
1561
1562 return found_task;
1563 }
1564
1569 void RemoveTask(KernelTask *task)
1570 {
1571 STK_ASSERT(task != nullptr);
1572
1573 #if STK_SEGGER_SYSVIEW
1574 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
1575 #endif
1576
1577 // notify task about pending exit
1578 task->GetUserTask()->OnExit();
1579
1580 m_strategy.RemoveTask(task);
1581 task->Unbind();
1582 }
1583
1594 __stk_attr_noinline void OnStart(Stack *&active) override
1595 {
1596 STK_ASSERT(m_strategy.GetSize() != 0);
1597
1598 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
1599 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1600 {
1601 for (size_t i = 0U; i < TASKS_MAX; ++i)
1602 {
1603 KernelTask *const task = &m_task_storage[i];
1604
1605 if (task->IsSleeping())
1606 {
1607 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1608 {
1609 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1610
1611 // notify strategy that task is sleeping
1612 m_strategy.OnTaskSleep(task);
1613 }
1614 }
1615 }
1616 }
1617
1618 // get initial state and first task
1619 {
1621
1622 KernelTask *next = nullptr;
1624
1625 // expecting only SLEEPING or SWITCHING states
1627
1629 {
1630 m_task_now = next;
1631 active = next->GetUserStackPtr();
1632
1634 {
1635 next->HrtOnSwitchedIn();
1636 }
1637 }
1638 else
1640 {
1642 active = &m_sleep_trap[0].stack;
1643 }
1644 else
1645 {
1646 // unexpected state
1648 }
1649 }
1650
1651 // is in running state
1653
1654 #if STK_SEGGER_SYSVIEW
1655 SEGGER_SYSVIEW_OnTaskStartExec(m_task_now->tid);
1656 #endif
1657 }
1658
1665 {
1667 {
1669
1670 // is in stopped state, i.e. is ready to Start() again
1672 }
1673 }
1674
1691 bool OnTick(Stack *&idle, Stack *&active
1692 #if STK_TICKLESS_IDLE
1693 , Timeout &ticks
1694 #endif
1695 ) override
1696 {
1697 #if !STK_TICKLESS_IDLE
1698 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
1699 enum { ticks = 1 };
1700 #endif
1701
1702 // advance internal timestamp
1703 m_service.IncrementTicks(ticks);
1704
1705 // consume elapsed and update to ticks to sleep
1706 #if STK_TICKLESS_IDLE
1707 ticks = (
1708 #else
1709 // notify compiler that we ignore a return value of UpdateTasks
1710 STK_UNUSED(
1711 #endif
1712 UpdateTasks(ticks));
1713
1714 // decide on a context switch
1715 return UpdateFsmState(idle, active);
1716 }
1717
1718 void OnTaskSwitch(Word caller_SP) override
1719 {
1720 OnTaskSleep(caller_SP, YIELD_TICKS);
1721 }
1722
1723 void OnTaskSleep(Word caller_SP, Timeout ticks) override
1724 {
1725 KernelTask *const task = FindTaskBySP(caller_SP);
1726 STK_ASSERT(task != nullptr);
1727
1728 // make change to HRT state and sleep time atomic
1729 {
1731
1733 {
1734 task->HrtOnWorkCompleted();
1735 }
1736
1737 if (ticks > 0)
1738 {
1739 task->ScheduleSleep(ticks);
1740 }
1741 }
1742
1743 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1744 task->BusyWaitWhileSleeping();
1745 }
1746
1747 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
1748 {
1749 KernelTask *const task = FindTaskBySP(caller_SP);
1750 STK_ASSERT(task != nullptr);
1751
1752 bool result = true;
1753
1754 // make change to HRT state and sleep time atomic
1755 {
1757
1758 // calculate signed delta (handles wrap-around correctly)
1759 const Ticks delta = timestamp - m_service.m_ticks;
1760
1761 if (delta > 0)
1762 {
1763 const Ticks infinite_ticks = WAIT_INFINITE;
1764 task->ScheduleSleep(static_cast<Timeout>(Min(delta, infinite_ticks)));
1765 }
1766 else
1767 {
1768 result = false; // deadline already hit or passed
1769 }
1770 }
1771
1772 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1773 task->BusyWaitWhileSleeping();
1774 return result;
1775 }
1776
1778 {
1779 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(task_id));
1780 if (task != nullptr)
1781 {
1783
1784 if (task->IsSleeping())
1785 {
1786 task->Wake();
1787 }
1788 }
1789 }
1790
1791 void OnTaskExit(Stack *stack) override
1792 {
1794 {
1795 KernelTask *const task = FindTaskByStack(stack);
1796 STK_ASSERT(task != nullptr);
1797
1798 // notify kernel to execute removal
1799 task->ScheduleRemoval();
1800 }
1801 else
1802 {
1803 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
1805 }
1806 }
1807
1808 EWaitResult OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
1809 {
1811 {
1812 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
1813 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
1814 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
1815 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
1816
1817 KernelTask *const task = FindTaskBySP(caller_SP);
1818 STK_ASSERT(task != nullptr);
1819
1820 // configure waiting
1821 task->m_wait_obj->SetupWait(sync_obj, timeout);
1822
1823 // register ISyncObject if not yet
1824 if (sync_obj->GetHead() == nullptr)
1825 {
1826 m_sync_list->LinkBack(sync_obj);
1827 }
1828
1829 // start sleeping infinitely, we rely on a Wake call via WaitObject
1830 task->ScheduleSleep(WAIT_INFINITE);
1831
1832 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
1833 mutex->Unlock();
1834
1835 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1836 task->BusyWaitWhileSleeping();
1837
1838 // re-lock mutex when returning to the task's execution space
1839 mutex->Lock();
1840
1841 return (task->m_wait_obj->IsTimeout() ? WAIT_RESULT_TIMEOUT : WAIT_RESULT_SIGNAL);
1842 }
1843 else
1844 {
1845 STK_ASSERT(false);
1846 return WAIT_RESULT_FAIL;
1847 }
1848 }
1849
1850 TId OnGetTid(Word caller_SP) override
1851 {
1852 KernelTask *const task = FindTaskBySP(caller_SP);
1853 STK_ASSERT(task != nullptr);
1854
1855 return task->GetTid();
1856 }
1857
1858 void OnSuspend(bool suspended) override
1859 {
1860 // toggle kernel state
1861 if (suspended)
1862 {
1863 if (m_kstate == KSTATE_RUNNING)
1864 {
1866 }
1867 }
1868 else
1869 {
1870 if (m_kstate == KSTATE_SUSPENDED)
1871 {
1873 }
1874 }
1875
1876 // force yield for a currently active task
1877 if (!m_task_now->IsSleeping())
1878 {
1879 m_task_now->ScheduleSleep(YIELD_TICKS);
1880 }
1881 }
1882
1883 void OnInheritWeight(TId tid, Weight weight)
1884 {
1885 STK_ASSERT(tid != TID_NONE);
1886 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1887
1888 if (weight != NO_WEIGHT)
1889 {
1890 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1891 STK_ASSERT(task != nullptr);
1892
1893 const Weight prev_weight = task->GetWeight();
1894
1895 if (prev_weight < weight)
1896 {
1897 task->SetCurrentWeight(weight);
1898 m_strategy.OnTaskWeightChange(task, prev_weight);
1899 }
1900 }
1901 }
1902
1904 {
1905 STK_ASSERT(tid != TID_NONE);
1906 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1907
1908 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1909 STK_ASSERT(task != nullptr);
1910
1911 const Weight prev_weight = task->GetWeight();
1912
1913 // restore to original or boost from wait objects
1914 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
1915
1916 m_strategy.OnTaskWeightChange(task, prev_weight);
1917 }
1918
1921 Timeout UpdateTasks(const Timeout elapsed_ticks)
1922 {
1923 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
1925 {
1926 UpdateSyncObjects(elapsed_ticks);
1927 }
1928
1929 if (m_request != REQ_NONE)
1930 {
1932 }
1933
1934 return UpdateTaskState(elapsed_ticks);
1935 }
1936
1946 Timeout UpdateTaskState(const Timeout elapsed_ticks)
1947 {
1949
1950 for (size_t i = 0U; i < TASKS_MAX; ++i)
1951 {
1952 KernelTask *const task = &m_task_storage[i];
1953
1954 if (task->IsSleeping())
1955 {
1957 {
1958 // task is pending removal, wait until it is switched out
1959 if (task->IsPendingRemoval())
1960 {
1961 const size_t tasks_left = m_strategy.GetSize();
1962
1963 if ((task != m_task_now) ||
1964 ((tasks_left == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
1965 {
1966 RemoveTask(task);
1967 continue;
1968 }
1969 }
1970 }
1971
1972 // deliver sleep event to strategy
1973 // note: only currently scheduled task can be pending to sleep
1974 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1975 {
1976 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1977 {
1978 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1979
1980 // notify strategy that task is sleeping
1981 m_strategy.OnTaskSleep(task);
1982 }
1983 }
1984
1985 // advance sleep time by a tick
1986 task->m_time_sleep += elapsed_ticks;
1987
1988 // deliver sleep event to strategy
1989 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1990 {
1991 // notify strategy that task woke up
1992 if (!task->IsSleeping())
1993 {
1994 m_strategy.OnTaskWake(task);
1995 }
1996 }
1997 }
1998 else
1999 {
2001 {
2002 // in HRT mode we trace how long task spent in active state (doing some work)
2003 if (task->IsBusy())
2004 {
2005 task->m_hrt[0].duration += elapsed_ticks;
2006
2007 // check if deadline is missed (HRT failure)
2008 if (task->HrtIsDeadlineMissed(task->m_hrt[0].duration))
2009 {
2010 // report deadline overrun to a strategy which supports overrun recovery
2011 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
2012 {
2013 if (!m_strategy.OnTaskDeadlineMissed(task))
2014 {
2015 // report failure if it could not be recovered by the scheduling strategy
2016 task->HrtHardFailDeadline(&m_platform);
2017 }
2018 }
2019 else
2020 {
2021 task->HrtHardFailDeadline(&m_platform);
2022 }
2023 }
2024 }
2025 }
2026 }
2027
2028 // get the number ticks the driver has to keep CPU in Idle
2030 {
2031 if ((sleep_ticks > 1) && task->IsBusy())
2032 {
2033 sleep_ticks = task->GetSleepTicks(sleep_ticks);
2034 }
2035 }
2036 }
2037
2038 return sleep_ticks;
2039 }
2040
2043 void UpdateSyncObjects(const Timeout elapsed_ticks)
2044 {
2045 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
2046
2047 while (itr != nullptr)
2048 {
2049 ISyncObject::ListEntryType *const next = itr->GetNext();
2050
2051 if (!util::DListCast::ListEntryToParent<ISyncObject>(itr)->Tick(elapsed_ticks))
2052 {
2053 m_sync_list->Unlink(itr);
2054 }
2055
2056 itr = next;
2057 }
2058 }
2059
2063 {
2064 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2065 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2067 {
2068 // process serialized AddTask request made from another active task, requesting process
2069 // is currently waiting due to SwitchToNext()
2070 if ((m_request & REQ_ADD_TASK) != 0U)
2071 {
2073
2074 for (size_t i = 0U; i < TASKS_MAX; ++i)
2075 {
2076 KernelTask *const task = &m_task_storage[i];
2077
2078 if (task->m_srt[0].add_task_req != nullptr)
2079 {
2080 AllocateAndAddNewTask(task->m_srt[0].add_task_req->user_task);
2081
2082 task->m_srt[0].add_task_req = nullptr;
2083 __stk_full_memfence();
2084 }
2085 }
2086 }
2087 }
2088 }
2089
2094 EFsmEvent FetchNextEvent(KernelTask *&next)
2095 {
2097
2098 // try getting next task for scheduling
2100
2101 // sleep-aware strategy returns nullptr if no active tasks available
2102 if (next != nullptr)
2103 {
2104 // strategy must provide active-only task
2105 STK_ASSERT(!next->IsSleeping());
2106
2107 // if was sleeping, process wake event first
2109 }
2110 // start sleeping
2111 else
2112 {
2114 {
2115 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2116 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2117 if (m_strategy.GetSize() == 0U)
2118 {
2119 next = nullptr;
2120 type = FSM_EVENT_EXIT;
2121 }
2122 }
2123 }
2124
2125 return type;
2126 }
2127
2132#ifdef _STK_UNDER_TEST
2133 virtual
2134#endif
2135 EFsmState GetNewFsmState(KernelTask *&next)
2136 {
2138 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2139 }
2140
2146 bool UpdateFsmState(Stack *&idle, Stack *&active)
2147 {
2148 KernelTask *const now = m_task_now, *next = nullptr;
2149 bool switch_context = false;
2150
2151 const EFsmState new_state = GetNewFsmState(next);
2152
2153 switch (new_state)
2154 {
2156 switch_context = StateSwitch(now, next, idle, active);
2157 m_fsm_state = new_state;
2158 break;
2159 case FSM_STATE_SLEEPING:
2160 switch_context = StateSleep(now, next, idle, active);
2161 m_fsm_state = new_state;
2162 break;
2163 case FSM_STATE_WAKING:
2164 switch_context = StateWake(now, next, idle, active);
2165 m_fsm_state = new_state;
2166 break;
2167 case FSM_STATE_EXITING:
2168 switch_context = StateExit(now, next, idle, active);
2169 m_fsm_state = new_state;
2170 break;
2171 case FSM_STATE_NONE:
2172 break; // valid intermittent non-persisting state: no-transition
2173 case FSM_STATE_MAX:
2174 default: // invalid state value
2176 break;
2177 }
2178
2179 return switch_context;
2180 }
2181
2189 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2190 {
2191 STK_ASSERT(now != nullptr);
2192 STK_ASSERT(next != nullptr);
2193
2194 bool switch_context = false;
2195
2196 // if equal: do not switch context because task did not change
2197 if (next != now)
2198 {
2199 idle = now->GetUserStackPtr();
2200 active = next->GetUserStackPtr();
2201
2202 // if stack memory is exceeded these assertions will be hit
2203 if (now->IsBusy())
2204 {
2205 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2206 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2207 }
2208 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2209
2210 m_task_now = next;
2211
2213 {
2214 if (now->m_hrt[0].done)
2215 {
2216 now->HrtOnSwitchedOut();
2217 next->HrtOnSwitchedIn();
2218 }
2219 }
2220
2221 #if STK_SEGGER_SYSVIEW
2222 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SWITCH);
2223 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2224 #endif
2225
2226 switch_context = true;
2227 }
2228
2229 return switch_context;
2230 }
2231
2239 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2240 {
2241 STK_UNUSED(now);
2242
2243 STK_ASSERT(next != nullptr);
2244
2245 idle = &m_sleep_trap[0].stack;
2246 active = next->GetUserStackPtr();
2247
2248 // if stack memory is exceeded these assertions will be hit
2250 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2251
2252 m_task_now = next;
2253
2254 #if STK_SEGGER_SYSVIEW
2255 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2256 #endif
2257
2259 {
2260 next->HrtOnSwitchedIn();
2261 }
2262
2263 return true; // switch context
2264 }
2265
2273 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2274 {
2275 STK_UNUSED(next);
2276
2277 STK_ASSERT(now != nullptr);
2278 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
2279
2280 idle = now->GetUserStackPtr();
2281 active = &m_sleep_trap[0].stack;
2282
2284
2285 #if STK_SEGGER_SYSVIEW
2286 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2287 #endif
2288
2290 {
2291 if (!now->IsPendingRemoval())
2292 {
2293 now->HrtOnSwitchedOut();
2294 }
2295 }
2296
2297 return true; // switch context
2298 }
2299
2308 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2309 {
2310 STK_UNUSED(now);
2311 STK_UNUSED(next);
2312
2314 {
2315 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
2316 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
2317
2318 idle = nullptr;
2319 active = &m_exit_trap[0].stack;
2320
2321 m_task_now = nullptr;
2322
2323 m_platform.Stop();
2324 }
2325 else
2326 {
2327 STK_UNUSED(idle);
2328 STK_UNUSED(active);
2329 }
2330
2331 return false;
2332 }
2333
2337 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
2338
2344 {
2347 }
2348
2349#if STK_SEGGER_SYSVIEW
2354 void SendTaskTraceInfo(KernelTask *task)
2355 {
2356 STK_ASSERT(task->IsBusy());
2357
2358 SEGGER_SYSVIEW_TASKINFO info =
2359 {
2360 .TaskID = task->GetUserStackPtr()->tid,
2361 .sName = task->GetUserTask()->GetTraceName(),
2362 .Prio = 0,
2363 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
2364 .StackSize = task->GetUserTask()->GetStackSize() * sizeof(Word)
2365 };
2366 SEGGER_SYSVIEW_SendTaskInfo(&info);
2367 }
2368#endif
2369
2370 // Kernel modes:
2371 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
2372 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
2373 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
2374 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
2375 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
2376
2377 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
2379
2380 // If hit here: Kernel mode must be assigned.
2381 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
2382
2383 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
2384 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
2385 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
2386
2387 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
2388 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
2389 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
2390
2391 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
2392 // which destroys the precise periodicity HRT depends on.
2393 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
2394 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
2395
2396 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
2397 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
2398 !TStrategy::PRIORITY_INHERITANCE_API);
2399
2404
2419
2435
2442
2443 KernelService m_service;
2444 TPlatform m_platform;
2445 TStrategy m_strategy;
2446 KernelTask *m_task_now;
2448 SleepTrapStack m_sleep_trap[1];
2451 volatile uint8_t m_request;
2454
2456 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
2461 };
2462
2464};
2465
2466} // namespace stk
2467
2468#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:136
@ TRACE_EVENT_SLEEP
Task entered sleep / blocked state.
Definition stk_common.h:116
@ TRACE_EVENT_SWITCH
Task context switch event (task became active).
Definition stk_common.h:115
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:44
static constexpr ITask * GetUserTaskFromTid(TId task_id) noexcept
Get task instance from its identifier.
Definition stk_arch.h:532
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:210
int64_t Ticks
Ticks value.
Definition stk_common.h:151
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:146
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:645
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:85
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:84
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:86
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:75
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:123
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:124
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:126
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:125
constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:220
constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:215
@ PERIODICITY_DEFAULT
Default periodicity (microseconds), 1 millisecond.
Definition stk_common.h:95
@ PERIODICITY_MAX
Maximum periodicity (microseconds), 99 milliseconds (note: this value is the highest working on a rea...
Definition stk_common.h:94
Timeout GetInitialSleepTicks()
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:204
constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:198
@ SYS_TASK_ID_EXIT
Exit trap.
Definition stk_common.h:105
@ SYS_TASK_ID_SLEEP
Sleep trap.
Definition stk_common.h:104
static constexpr T Min(T a, T b)
Compile-time minimum of two values.
Definition stk_defs.h:639
static constexpr TId GetTidFromUserTask(const ITask *task) noexcept
Get task identifier from ITask instance.
Definition stk_arch.h:526
uint64_t Cycles
Cycles value.
Definition stk_common.h:161
Word TId
Task (thread) id.
Definition stk_common.h:141
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:166
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
Definition stk_common.h:57
@ KERNEL_SYNC
Synchronization support (see Event).
Definition stk_common.h:56
@ KERNEL_HRT
Hard Real-Time (HRT) behavior (tasks are scheduled periodically and have an execution deadline,...
Definition stk_common.h:55
@ KERNEL_STATIC
All tasks are static and can not exit.
Definition stk_common.h:53
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
Definition stk_common.h:54
@ KERNEL_PANIC_BAD_MODE
Kernel is in bad/unsupported mode for the current operation.
Definition stk_common.h:74
@ KERNEL_PANIC_BAD_STATE
Kernel entered unexpected (bad) state.
Definition stk_common.h:73
Memory-related primitives.
static __stk_forceinline void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:288
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:223
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:1664
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2146
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1379
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1463
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:1791
void OnTaskSleepCancel(TId task_id)
Definition stk.h:1777
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1305
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:1508
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:2403
~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:1691
EWaitResult 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:1808
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:1858
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1116
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2135
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel when it is not started.
Definition stk.h:1091
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:1903
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:1594
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:2239
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:1529
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1345
static constexpr bool IsHrtMode()
Definition stk.h:2373
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:1027
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:2441
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1319
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:1201
static constexpr bool IsSyncMode()
Definition stk.h:2374
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance.
Definition stk.h:1487
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1337
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:1883
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1181
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:1723
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1253
static constexpr bool IsTicklessMode()
Definition stk.h:2375
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:1569
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1419
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1297
ERequest
Bitmask flags for pending inter-task requests that must be processed by the kernel on the next tick (...
Definition stk.h:104
bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Exits from scheduling.
Definition stk.h:2308
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1288
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1434
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:1718
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:990
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:1449
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:1850
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1225
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:1921
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:2343
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:2337
static constexpr bool IsDynamicMode()
Definition stk.h:2372
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1293
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2189
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:1066
Kernel()
Construct the kernel with all storage zero-initialized and the request flag set to ~0 (indicating uni...
Definition stk.h:957
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2062
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:2273
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, advance sleep timers, and track HRT durations.
Definition stk.h:1946
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:2043
static constexpr bool IsStaticMode()
Definition stk.h:2371
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1280
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:1747
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1144
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2094
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:730
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:673
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:716
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:766
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:763
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:768
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:693
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:648
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:764
void BusyWaitWhileSleeping() const
Block further execution of the task's context while in sleeping state.
Definition stk.h:749
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:762
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:760
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:767
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:707
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:765
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:668
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:769
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:914
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:869
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:849
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:942
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:792
friend class Kernel
Definition stk.h:781
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:809
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:941
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:786
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:841
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:882
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:825
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:902
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:894
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:790
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:788
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:794
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:784
EWaitResult 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:856
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:935
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:927
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2413
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:2414
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:2417
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2416
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2429
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:2433
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:2430
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2432
RAII guard that enters the critical section on construction and exits it on destruction.
Definition stk_arch.h:363
Lightweight, non-owning view over a contiguous sequence of elements.
Definition stk_common.h:247
size_t GetSize() const
Get number of elements in the view.
Definition stk_common.h:271
Stack descriptor.
Definition stk_common.h:302
uint32_t access_mode
Bitfield with hardware access mode of the task (see EAccessMode).
Definition stk_common.h:304
Interface for a stack memory region.
Definition stk_common.h:319
virtual size_t GetStackSize() const =0
Get number of elements of the stack memory array.
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Wait object.
Definition stk_common.h:362
Synchronization object.
Definition stk_common.h:456
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:469
DLHeadType ListHeadType
List head type for ISyncObject elements.
Definition stk_common.h:464
static void AddWaitObject(IWaitObject::ListHeadType &wlist, IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:475
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:208
Interface for mutex synchronization primitive.
Definition stk_common.h:613
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:670
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:228
virtual void OnExit()
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
Definition stk_common.h:715
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:748
Interface for a platform driver.
Definition stk_common.h:840
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
Definition stk_common.h:848
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:135
StackMemoryDef< _StackSize >::Type MemoryType
Definition stk_helper.h:140
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.