SuperTinyKernel™ RTOS 1.08.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
37// Helper function for Kernel::UpdateTaskState.
38template <bool TicklessMode> __stk_forceinline Timeout GetInitialSleepTicks();
41
84template <uint8_t TMode, uint32_t TSize, class TStrategy, class TPlatform>
85class Kernel
86#ifndef _STK_UNDER_TEST
87final
88#endif
89: public IKernel, private IPlatform::IEventHandler
90{
91protected:
97
103
108 enum ERequest : uint8_t
109 {
111 REQ_ADD_TASK = (1 << 0)
112 };
113
125 class KernelTask final : public IKernelTask
126 {
127 friend class Kernel;
128
133 enum EStateFlags : uint32_t
134 {
139 };
140
141 public:
150 {
152 };
153
159 m_srt(), m_hrt(), m_rt_weight()
160 {
161 // bind to wait object
163 {
164 m_wait_obj->m_task = this;
165 }
166 }
167
171 ITask *GetUserTask() override { return m_user; }
172
176 Stack GetUserStack() const override { return m_stack;}
177
181 bool IsBusy() const { return (m_user != nullptr); }
182
186 __stk_forceinline bool IsSleeping() const override { return (m_time_sleep < 0); }
187
192
196 TId GetTid() const { return GetTidFromUserTask(m_user); }
197
202 void Wake() override
203 {
205
206 // wakeup on a next cycle
207 m_time_sleep = -1;
208
209 // notify kernel that this task, even if was going to sleep will be woken on a next tick
210 if ((m_state & STATE_SLEEP_PENDING) != 0U)
211 {
213 }
214 }
215
219 void SetCurrentWeight(Weight weight) override
220 {
221 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
222 {
223 m_rt_weight[0] = weight;
224 }
225 }
226
230 Weight GetWeight() const override
231 {
232 Weight static_weight;
233
234 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
235 {
236 if (m_rt_weight[0] != NO_WEIGHT)
237 {
238 static_weight = m_rt_weight[0];
239 }
240 else
241 {
242 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
243 {
244 static_weight = m_user->GetWeight();
245 }
246 else
247 {
248 static_weight = DEFAULT_WEIGHT;
249 }
250 }
251 }
252 else if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
253 {
254 static_weight = m_user->GetWeight();
255 }
256 else
257 {
258 static_weight = DEFAULT_WEIGHT;
259 }
260
261 return static_weight;
262 }
263
269 Weight GetCurrentWeight() const override
270 {
271 Weight cur_weight;
272
273 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
274 {
275 cur_weight = m_rt_weight[0];
276 }
277 else
278 {
279 cur_weight = DEFAULT_WEIGHT;
280 }
281
282 return cur_weight;
283 }
284
289 Timeout GetHrtPeriodicity() const override
290 {
292
293 Timeout to;
294
296 {
297 to = m_hrt[0].periodicity;
298 }
299 else
300 {
301 to = 0;
302 }
303
304 return to;
305 }
306
312 Timeout GetHrtDeadline() const override
313 {
315
316 Timeout deadline;
317
319 {
320 deadline = m_hrt[0].deadline;
321 }
322 else
323 {
324 deadline = 0;
325 }
326
327 return deadline;
328 }
329
338 {
341
342 Timeout relative_deadline;
343
345 {
346 relative_deadline = (m_hrt[0].deadline - m_hrt[0].duration);
347 }
348 else
349 {
350 relative_deadline = 0;
351 }
352
353 return relative_deadline;
354 }
355
357 {
358 // note: task sleep time is negative
360
362 {
363 // likely task is sleeping during sync operation (see Wait)
364 if (m_wait_obj->IsWaiting())
365 {
366 // note: sync wait time is positive
367 task_sleep = m_wait_obj->m_time_wait;
368
369 // we shall account for only valid time (when task is waiting during sync operation)
370 if (task_sleep > NO_WAIT)
371 {
372 sleep_ticks = Min(sleep_ticks, task_sleep);
373 }
374 }
375 else
376 {
377 sleep_ticks = Min(sleep_ticks, task_sleep);
378 }
379 }
380 else
381 {
382 sleep_ticks = Min(sleep_ticks, task_sleep);
383 }
384
385 // clamp to [1, STK_TICKLESS_TICKS_MAX] range
386 return Max<Timeout>(1, sleep_ticks);
387 }
388
389 protected:
394
400 struct SrtInfo
401 {
403 {}
404
407 void Clear()
408 {
409 add_task_req = nullptr;
410 }
411
418 };
419
424 struct HrtInfo
425 {
426 HrtInfo() : periodicity(0), deadline(0), duration(0), done(false)
427 {}
428
431 void Clear()
432 {
433 periodicity = 0;
434 deadline = 0;
435 duration = 0;
436 done = false;
437 }
438
442 volatile bool done;
443 };
444
451 struct WaitObject final : public IWaitObject
452 {
453 explicit WaitObject() : m_task(nullptr), m_sync_obj(nullptr), m_timeout(false), m_time_wait(NO_WAIT)
454 {}
455
460
467 {
469 };
470
474 TId GetTid() const override { return m_task->GetTid(); }
475
479 bool IsTimeout() const override { return m_timeout; }
480
484 bool IsWaiting() const { return (m_sync_obj != nullptr); }
485
491 void Wake(bool timeout) override
492 {
494
495 m_timeout = timeout;
497
498 m_sync_obj->RemoveWaitObject(this);
499 m_sync_obj = nullptr;
500
501 return m_task->Wake();
502 }
503
510 bool Tick(Timeout elapsed_ticks) override
511 {
513 {
514 if (!m_timeout)
515 {
516 m_time_wait -= elapsed_ticks;
517
518 if (m_time_wait <= NO_WAIT)
519 {
520 m_timeout = true;
521 }
522 }
523 }
524
525 return !m_timeout;
526 }
527
535 void SetupWait(ISyncObject *sync_obj, Timeout timeout)
536 {
538
539 m_sync_obj = sync_obj;
540 m_time_wait = timeout;
541 m_timeout = false;
542
543 sync_obj->AddWaitObject(this);
544 }
545
548 volatile bool m_timeout;
550 };
551
556 void Bind(TPlatform *platform, ITask *user_task)
557 {
558 // bind user task (GetTid depends on m_user)
559 m_user = user_task;
560
561 // set access mode for this stack
562 m_stack.access_mode = user_task->GetAccessMode();
563
564 // set task id for tracking purpose
565 #if STK_STACK_NEEDS_TASK_ID
566 m_stack.tid = GetTid();
568 #endif
569
570 // init stack of the user task
571 platform->InitStack(STACK_USER_TASK, &m_stack, user_task, user_task);
572
573 // initialize current weight to NO_WEIGHT for priority inheritance mechanism
574 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
575 {
577 }
578 }
579
583 void Unbind()
584 {
586 {
587 // should be freed from waiting on task exit
588 STK_ASSERT(!m_wait_obj->IsWaiting());
589 }
590
591 m_user = nullptr;
592 m_stack = {};
594 m_time_sleep = 0;
595
597 {
598 m_hrt[0].Clear();
599 }
600 else
601 {
602 m_srt->Clear();
603 }
604 }
605
609 {
610 // make this task sleeping to switch it out from scheduling process
612
613 // mark it as done HRT task
615 {
617 }
618
619 // mark it as pending for removal
621 }
622
625 bool IsPendingRemoval() const { return ((m_state & STATE_REMOVE_PENDING) != 0U); }
626
630 bool IsMemoryOfSP(Word SP) const
631 {
632 bool is_match = false;
633
634 const Word start = hw::PtrToWord(m_user->GetStack());
635 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
636
637 if ((SP >= start) && (SP <= end))
638 {
639 is_match = true;
640 }
641 #if STK_TZ_SECURE // lookup Secure memory region too when on a Secure side
642 else
643 {
644 IStackMemory *const secure_mem = m_user->GetSecureStackMemory();
645
646 if (secure_mem != nullptr)
647 {
648 const Word s_start = hw::PtrToWord(secure_mem->GetStack());
649 const Word s_end = s_start + (secure_mem->GetStackSize() * sizeof(Word));
650
651 if ((SP >= s_start) && (SP <= s_end))
652 {
653 is_match = true;
654 }
655 }
656 }
657 #endif
658
659 return is_match;
660 }
661
668 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
669 {
670 STK_ASSERT(periodicity_tc > 0);
671 STK_ASSERT(deadline_tc > 0);
672 STK_ASSERT(start_delay_tc >= 0);
673 STK_ASSERT(periodicity_tc < INT32_MAX);
674 STK_ASSERT(deadline_tc < INT32_MAX);
675
676 m_hrt[0].periodicity = periodicity_tc;
677 m_hrt[0].deadline = deadline_tc;
678
679 if (start_delay_tc > 0)
680 {
681 ScheduleSleep(start_delay_tc);
682 }
683 }
684
689
694 {
695 const Timeout duration = m_hrt[0].duration;
696
697 STK_ASSERT(duration >= 0);
698
699 const Timeout sleep = m_hrt[0].periodicity - duration;
700 if (sleep > 0)
701 {
702 ScheduleSleep(sleep);
703 }
704
705 m_hrt[0].duration = 0;
706 m_hrt[0].done = false;
707 }
708
714 {
715 const Timeout duration = m_hrt[0].duration;
716
717 STK_ASSERT(duration >= 0);
719
720 m_user->OnDeadlineMissed(duration);
721 platform->ProcessHardFault();
722 }
723
728 {
729 m_hrt[0].done = true;
730 __stk_full_memfence();
731 }
732
736 bool HrtIsDeadlineMissed(Timeout duration) const
737 {
738 return (duration > m_hrt[0].deadline);
739 }
740
751 {
752 STK_ASSERT(ticks > 0);
753
754 // set state first as kernel checks it when task IsSleeping
755 if (!IsSleeping())
756 {
758 }
759
760 m_time_sleep = -ticks;
761
762 __stk_full_memfence();
763 }
764
767 void BusyWaitWhileSleeping(Kernel *kernel) const
768 {
769 kernel->m_platform.ForceContextSwitch(GetTid());
770
771 while (IsSleeping())
772 {
773 __stk_relax_cpu();
774 }
775 }
776
781
784 volatile uint32_t m_state;
790 };
791
799 class KernelService final : public IKernelService
800 {
801 friend class Kernel;
802
803 public:
804 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
805
806 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
807
808 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
809
810 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
811
812 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
813
814 void Delay(Timeout ticks) override
815 {
817 STK_ASSERT(ticks >= 0);
818
819 Ticks now = GetTicks();
820 const Ticks deadline = now + ticks;
821 STK_ASSERT(deadline >= now);
822
823 for (; now < deadline; now = GetTicks())
824 {
825 __stk_relax_cpu();
826 }
827 }
828
829 void Sleep(Timeout ticks) override
830 {
832 STK_ASSERT(ticks >= 0);
833
835 {
836 m_kernel->m_platform.Sleep(ticks);
837 }
838 else
839 {
840 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
841 STK_ASSERT(false);
842 }
843 }
844
845 bool SleepUntil(Ticks timestamp) override
846 {
848
850 {
851 return m_kernel->m_platform.SleepUntil(timestamp);
852 }
853 else
854 {
855 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
856 STK_ASSERT(false);
857 return false;
858 }
859 }
860
861 void SleepCancel(TId task_id) override
862 {
864 {
865 m_kernel->OnTaskSleepCancel(task_id);
866 }
867 }
868
869 void SwitchToNext() override
870 {
872
873 m_kernel->m_platform.SwitchToNext();
874 }
875
876 EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
877 {
879 {
880 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
881 }
882 else
883 {
884 STK_ASSERT(false);
885 return WAIT_RESULT_FAIL;
886 }
887 }
888
889 void Wake(ISyncObject *sobj, bool all) override
890 {
892 {
893 if (all)
894 {
896 }
897 else
898 {
900 }
901 }
902 else
903 {
904 STK_ASSERT(false);
905 }
906 }
907
908 Timeout Suspend() override
909 {
911 {
912 return m_kernel->m_platform.Suspend();
913 }
914 else
915 {
916 STK_ASSERT(false);
917 return 0;
918 }
919 }
920
921 void Resume(Timeout elapsed_ticks) override
922 {
924 {
925 return m_kernel->m_platform.Resume(elapsed_ticks);
926 }
927 else
928 {
929 STK_ASSERT(false);
930 }
931 }
932
933 void InheritWeight(TId tid, Weight weight) override
934 {
935 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API)
936 {
937 m_kernel->OnInheritWeight(tid, weight);
938 }
939 }
940
941 void RestoreWeight(TId tid, ISyncObject *sobj) override
942 {
943 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API)
944 {
945 m_kernel->OnRestoreWeight(tid, sobj);
946 }
947 }
948
949 private:
953 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
954 {}
955
960
966 void Initialize(Kernel *kernel)
967 {
968 m_kernel = kernel;
969 }
970
974 void IncrementTicks(Ticks advance)
975 {
976 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
978 }
979
981 volatile Ticks m_ticks;
982 };
983
984public:
987 static constexpr size_t TASKS_MAX = TSize;
988
999 {
1000 #ifdef _DEBUG
1001 // TPlatform must inherit IPlatform
1002 IPlatform *platform = &m_platform;
1003 STK_UNUSED(platform);
1004
1005 // TStrategy must inherit ITaskSwitchStrategy
1006 ITaskSwitchStrategy *strategy = &m_strategy;
1007 STK_UNUSED(strategy);
1008 #endif
1009
1010 #if !STK_TICKLESS_IDLE
1011 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
1012 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
1013 #endif
1014 }
1015
1020
1030 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
1031 {
1032 STK_ASSERT(resolution_us != 0);
1033 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
1035
1036 // reinitialize key state variables
1037 m_task_now = nullptr;
1040
1041 // exit trap is required only for KERNEL_DYNAMIC mode
1042 Stack *exit_trap;
1044 {
1045 exit_trap = &m_exit_trap[0].stack;
1046 }
1047 else
1048 {
1049 exit_trap = nullptr;
1050 }
1051
1052 m_service.Initialize(this);
1053 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
1054
1055 // now ready to Start()
1057 }
1058
1067 __stk_attr_noinline void AddTask(ITask *user_task) override
1068 {
1070 {
1071 STK_ASSERT(user_task != nullptr);
1073
1074 // when started the operation must be serialized by switching out from processing until
1075 // kernel processes this request
1076 if (IsStarted())
1077 {
1079 {
1080 RequestAddTask(user_task);
1081 }
1082 else
1083 {
1084 STK_ASSERT(false);
1085 }
1086 }
1087 else
1088 {
1089 AllocateAndAddNewTask(user_task);
1090 }
1091 }
1092 else
1093 {
1094 STK_ASSERT(false);
1095 }
1096 }
1097
1106 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1107 Timeout start_delay_tc) override
1108 {
1110 {
1111 STK_ASSERT(user_task != nullptr);
1114
1115 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1116 }
1117 else
1118 {
1119 STK_ASSERT(false);
1120 }
1121 }
1122
1131 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1132 {
1134 {
1135 STK_ASSERT(user_task != nullptr);
1137
1138 KernelTask *const task = FindTaskByUserTask(user_task);
1139 if (task != nullptr)
1140 {
1141 RemoveTask(task);
1142 }
1143 }
1144 else
1145 {
1146 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1147 STK_ASSERT(false);
1148 }
1149 }
1150
1157 {
1159 {
1160 STK_ASSERT(user_task != nullptr);
1162
1164
1165 KernelTask *const task = FindTaskByUserTask(user_task);
1166 if (task != nullptr)
1167 {
1168 task->ScheduleRemoval();
1169 }
1170 }
1171 else
1172 {
1173 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1174 STK_ASSERT(false);
1175 }
1176 }
1177
1184 void SuspendTask(ITask *user_task, bool &suspended) override
1185 {
1186 STK_ASSERT(user_task != nullptr);
1187
1188 bool self = false;
1189
1190 // avoid race with OnTick
1191 {
1193
1194 KernelTask *const task = FindTaskByUserTask(user_task);
1195 STK_ASSERT(task != nullptr);
1196
1197 // only suspend if the task is currently awake: if it is already sleeping
1198 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1199 // that would corrupt the original sleep state and, for sync-object waits,
1200 // would interfere with WaitObject::Tick()
1201 suspended = !task->IsSleeping();
1202 if (suspended == true)
1203 {
1204 task->ScheduleSleep(WAIT_INFINITE);
1205
1206 // check if suspending self
1207 self = (task == m_task_now);
1208
1209 // trace blocked via Suspend
1210 if (self)
1211 {
1212 #if STK_SEGGER_SYSVIEW
1213 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SUSPEND);
1214 #endif
1215 }
1216 }
1217 }
1218
1219 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1220 if (self)
1221 {
1222 m_task_now->BusyWaitWhileSleeping(this);
1223 }
1224 }
1225
1229 void ResumeTask(ITask *user_task) override
1230 {
1231 STK_ASSERT(user_task != nullptr);
1232
1233 // avoid race with OnTick
1235
1236 KernelTask *const task = FindTaskByUserTask(user_task);
1237 STK_ASSERT(task != nullptr);
1238
1239 if (task->IsSleeping())
1240 {
1241 task->Wake();
1242 }
1243 }
1244
1250 {
1251 size_t count = 0U;
1252 const size_t limit = Min(tasks.GetSize(), TASKS_MAX);
1253
1254 // avoid race with OnTick
1256
1257 for (size_t i = 0U; i < limit; ++i)
1258 {
1259 KernelTask *const task = &m_task_storage[i];
1260 if (task->IsBusy())
1261 {
1262 tasks[count++] = task;
1263 }
1264 }
1265
1266 return count;
1267 }
1268
1273 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1274 {
1275 size_t count = 0U;
1276 const size_t limit = Min(user_tasks.GetSize(), TASKS_MAX);
1277
1278 // avoid race with OnTick
1280
1281 for (size_t i = 0U; i < limit; ++i)
1282 {
1283 KernelTask *const task = &m_task_storage[i];
1284 if (task->IsBusy())
1285 {
1286 user_tasks[count++] = task->GetUserTask();
1287 }
1288 }
1289
1290 return count;
1291 }
1292
1302 {
1304
1305 // stacks of the traps must be re-initilized on every subsequent Start
1306 InitTraps();
1307
1308 // start tracing
1309 #if STK_SEGGER_SYSVIEW
1310 SEGGER_SYSVIEW_Start();
1311 for (size_t i = 0U; i < TASKS_MAX; ++i)
1312 {
1313 KernelTask *task = &m_task_storage[i];
1314 if (task->IsBusy())
1315 {
1316 SendTaskTraceInfo(task);
1317 }
1318 }
1319 #endif
1320
1321 m_platform.Start();
1322 }
1323
1328 bool IsStarted() const
1329 {
1330 return (m_task_now != nullptr);
1331 }
1332
1336 IPlatform *GetPlatform() override { return &m_platform; }
1337
1342
1345 EKernelState GetState() const override { return m_kstate; }
1346
1347 // Used by tests only, not Public API:
1348#ifdef _STK_UNDER_TEST
1349 void ScheduleSleepOnActiveTask(Timeout ticks)
1350 {
1351 m_task_now->ScheduleSleep(ticks);
1352 }
1353#endif
1354
1355protected:
1369
1382
1389 static constexpr Timeout YIELD_TICKS = 1;
1390
1394 {
1395 return ((state > FSM_STATE_NONE) && (state < FSM_STATE_MAX));
1396 }
1397
1401 {
1402 // init stack for a Sleep trap
1403 {
1404 SleepTrapStack &sleep = m_sleep_trap[0];
1405
1406 SleepTrapStackMemory wrapper(&sleep.memory);
1407 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1408 #if STK_STACK_NEEDS_TASK_ID
1409 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1410 #endif
1411
1412 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1413 }
1414
1415 // init stack for an Exit trap
1417 {
1418 ExitTrapStack &exit = m_exit_trap[0];
1419
1420 ExitTrapStackMemory wrapper(&exit.memory);
1421 exit.stack.access_mode = ACCESS_PRIVILEGED;
1422 #if STK_STACK_NEEDS_TASK_ID
1423 exit.stack.tid = SYS_TASK_ID_EXIT;
1424 #endif
1425
1426 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1427 }
1428 }
1429
1434 KernelTask *AllocateNewTask(ITask *user_task)
1435 {
1436 // look for a free kernel task
1437 KernelTask *new_task = nullptr;
1438 for (size_t i = 0U; i < TASKS_MAX; ++i)
1439 {
1440 KernelTask *const task = &m_task_storage[i];
1441 if (task->IsBusy())
1442 {
1443 // avoid task collision
1444 STK_ASSERT(task->m_user != user_task);
1445
1446 // avoid stack collision
1447 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1448 }
1449 else
1450 if (new_task == nullptr)
1451 {
1452 new_task = task;
1453 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1454 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1455 #endif
1456 }
1457 else
1458 {
1459 // noop, continue to the next slot
1460 }
1461 }
1462
1463 // if nullptr - exceeded max supported kernel task count, application design failure
1464 STK_ASSERT(new_task != nullptr);
1465
1466 new_task->Bind(&m_platform, user_task);
1467
1468 return new_task;
1469 }
1470
1474 void AddKernelTask(KernelTask *task)
1475 {
1476 #if STK_SEGGER_SYSVIEW
1477 // start tracing new task
1478 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1479 if (IsStarted())
1480 {
1481 SendTaskTraceInfo(task);
1482 }
1483 #endif
1484
1485 m_strategy.AddTask(task);
1486 }
1487
1492 {
1493 KernelTask *const task = AllocateNewTask(user_task);
1494 STK_ASSERT(task != nullptr);
1495
1496 AddKernelTask(task);
1497 }
1498
1506 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1507 {
1508 KernelTask *const task = AllocateNewTask(user_task);
1509 STK_ASSERT(task != nullptr);
1510
1511 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1512
1513 AddKernelTask(task);
1514 }
1515
1521 {
1522 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1523 STK_ASSERT(caller != nullptr);
1524
1525 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1526 caller->m_srt[0].add_task_req = &req;
1527
1528 // notify kernel
1530
1531 // switch out and wait for completion (due to context switch request could be processed here)
1532 if (caller->m_srt[0].add_task_req != nullptr)
1533 {
1534 m_service.SwitchToNext();
1535 }
1536
1537 STK_ASSERT(caller->m_srt[0].add_task_req == nullptr);
1538 }
1539
1544 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
1545 {
1546 KernelTask *found_task = nullptr;
1547
1548 for (size_t i = 0U; i < TASKS_MAX; ++i)
1549 {
1550 KernelTask *const task = &m_task_storage[i];
1551 if (task->GetUserTask() == user_task)
1552 {
1553 found_task = task;
1554 break;
1555 }
1556 }
1557
1558 return found_task;
1559 }
1560
1565 KernelTask *FindTaskByStack(const Stack *stack)
1566 {
1567 KernelTask *found_task = nullptr;
1568
1569 for (size_t i = 0U; i < TASKS_MAX; ++i)
1570 {
1571 KernelTask *const task = &m_task_storage[i];
1572 if (task->GetUserStackPtr() == stack)
1573 {
1574 found_task = task;
1575 break;
1576 }
1577 }
1578
1579 return found_task;
1580 }
1581
1587 {
1588 STK_ASSERT(m_task_now != nullptr);
1589
1590 KernelTask *found_task = nullptr;
1591
1592 if (m_task_now->IsMemoryOfSP(SP))
1593 {
1594 found_task = m_task_now;
1595 }
1596 else
1597 {
1598 for (size_t i = 0U; i < TASKS_MAX; ++i)
1599 {
1600 KernelTask *const task = &m_task_storage[i];
1601
1602 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
1604 {
1605 if (!task->IsBusy())
1606 {
1607 continue;
1608 }
1609 }
1610
1611 if (task->IsMemoryOfSP(SP))
1612 {
1613 found_task = task;
1614 break;
1615 }
1616 }
1617 }
1618
1619 return found_task;
1620 }
1621
1626 void RemoveTask(KernelTask *task)
1627 {
1628 STK_ASSERT(task != nullptr);
1629
1630 #if STK_SEGGER_SYSVIEW
1631 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
1632 #endif
1633
1634 // notify task about pending exit
1635 task->GetUserTask()->OnExit();
1636
1637 m_strategy.RemoveTask(task);
1638 task->Unbind();
1639 }
1640
1651 __stk_attr_noinline void OnStart(Stack *&active) override
1652 {
1653 STK_ASSERT(m_strategy.GetSize() != 0);
1654
1655 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
1656 for (size_t i = 0U; i < TASKS_MAX; ++i)
1657 {
1658 KernelTask *const task = &m_task_storage[i];
1659
1660 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1661 {
1662 STK_ASSERT(task->IsSleeping());
1663
1664 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1665
1666 // notify strategy that task is sleeping
1667 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1668 {
1669 m_strategy.OnTaskSleep(task);
1670 }
1671 }
1672 }
1673
1674 // get initial state and first task
1675 {
1677
1678 KernelTask *next = nullptr;
1680
1681 // expecting only SLEEPING or SWITCHING states
1683
1685 {
1686 m_task_now = next;
1687 active = next->GetUserStackPtr();
1688
1690 {
1691 next->HrtOnSwitchedIn();
1692 }
1693 }
1694 else
1696 {
1698 active = &m_sleep_trap[0].stack;
1699 }
1700 else
1701 {
1702 // unexpected state
1704 }
1705 }
1706
1707 // is in running state
1709 }
1710
1717 {
1719 {
1721
1722 // is in stopped state, i.e. is ready to Start() again
1724 }
1725 }
1726
1743 bool OnTick(Stack *&idle, Stack *&active
1744 #if STK_TICKLESS_IDLE
1745 , Timeout &ticks
1746 #endif
1747 ) override
1748 {
1749 #if !STK_TICKLESS_IDLE
1750 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
1751 enum { ticks = 1 };
1752 #endif
1753
1754 // advance internal timestamp
1755 m_service.IncrementTicks(ticks);
1756
1757 // consume elapsed and update to ticks to sleep
1758 #if STK_TICKLESS_IDLE
1759 ticks = (
1760 #else
1761 // notify compiler that we ignore a return value of UpdateTasks
1762 STK_UNUSED(
1763 #endif
1764 UpdateTasks(ticks));
1765
1766 // decide on a context switch
1767 return UpdateFsmState(idle, active);
1768 }
1769
1770 bool OnForceContextSwitch(TId id, Stack *&idle, Stack *&active)
1771 {
1772 bool switch_context = false;
1773 KernelTask *const task = m_task_now;
1774
1775 // note: called from inside ISR, therefore protection by critical section is not needed
1776
1777 // current task is busy-waiting to be de-scheduled
1778 if ((task->GetTid() == id) && task->IsSleeping())
1779 {
1780 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1781 {
1783
1784 switch_context = UpdateFsmState(idle, active);
1785 }
1786 }
1787
1788 return switch_context;
1789 }
1790
1791 void OnTaskSwitch(Word caller_SP) override
1792 {
1793 OnTaskSleep(caller_SP, YIELD_TICKS);
1794 }
1795
1796 void OnTaskSleep(Word caller_SP, Timeout ticks) override
1797 {
1798 KernelTask *const task = FindTaskBySP(caller_SP);
1799 STK_ASSERT(task != nullptr);
1800
1801 // make change to HRT state and sleep time atomic
1802 {
1804
1806 {
1807 task->HrtOnWorkCompleted();
1808 }
1809
1810 if (ticks > 0)
1811 {
1812 task->ScheduleSleep(ticks);
1813
1814 // trace blocked on Sleep
1815 #if STK_SEGGER_SYSVIEW
1816 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
1817 #endif
1818 }
1819 }
1820
1821 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1822 task->BusyWaitWhileSleeping(this);
1823 }
1824
1825 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
1826 {
1827 KernelTask *const task = FindTaskBySP(caller_SP);
1828 STK_ASSERT(task != nullptr);
1829
1830 bool result = true;
1831
1832 // make change to HRT state and sleep time atomic
1833 {
1835
1836 // calculate signed delta (handles wrap-around correctly)
1837 const Ticks delta = timestamp - m_service.m_ticks;
1838
1839 if (delta > 0)
1840 {
1841 const Ticks infinite_ticks = WAIT_INFINITE;
1842 task->ScheduleSleep(static_cast<Timeout>(Min(delta, infinite_ticks)));
1843
1844 // trace blocked on on SleepUntil
1845 #if STK_SEGGER_SYSVIEW
1846 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
1847 #endif
1848 }
1849 else
1850 {
1851 result = false; // deadline already hit or passed
1852 }
1853 }
1854
1855 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1856 if (result)
1857 {
1858 task->BusyWaitWhileSleeping(this);
1859 }
1860
1861 return result;
1862 }
1863
1865 {
1866 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(task_id));
1867 if (task != nullptr)
1868 {
1870
1871 if (task->IsSleeping())
1872 {
1873 task->Wake();
1874 }
1875 }
1876 }
1877
1878 void OnTaskExit(Stack *stack) override
1879 {
1881 {
1882 KernelTask *const task = FindTaskByStack(stack);
1883 STK_ASSERT(task != nullptr);
1884
1885 // task is being stopped and will terminate
1886 #if STK_SEGGER_SYSVIEW
1887 SEGGER_SYSVIEW_OnTaskStopExec();
1888 #endif
1889
1890 // notify kernel to execute removal
1891 task->ScheduleRemoval();
1892 }
1893 else
1894 {
1895 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
1897 }
1898 }
1899
1900 EWaitResult OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
1901 {
1903 {
1904 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
1905 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
1906 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
1907 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
1908
1909 KernelTask *const task = FindTaskBySP(caller_SP);
1910 STK_ASSERT(task != nullptr);
1911
1912 // configure waiting
1913 task->m_wait_obj->SetupWait(sync_obj, timeout);
1914
1915 // register ISyncObject if not yet
1916 if (sync_obj->GetHead() == nullptr)
1917 {
1918 m_sync_list->LinkBack(sync_obj);
1919 }
1920
1921 // start sleeping infinitely, we rely on a Wake call via WaitObject
1922 task->ScheduleSleep(WAIT_INFINITE);
1923
1924 // trace blocked on sync object's Wait
1925 #if STK_SEGGER_SYSVIEW
1926 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_WAIT);
1927 #endif
1928
1929 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
1930 mutex->Unlock();
1931
1932 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1933 task->BusyWaitWhileSleeping(this);
1934
1935 // re-lock mutex when returning to the task's execution space
1936 mutex->Lock();
1937
1938 return (task->m_wait_obj->IsTimeout() ? WAIT_RESULT_TIMEOUT : WAIT_RESULT_SIGNAL);
1939 }
1940 else
1941 {
1942 STK_ASSERT(false);
1943 return WAIT_RESULT_FAIL;
1944 }
1945 }
1946
1947 TId OnGetTid(Word caller_SP) override
1948 {
1949 KernelTask *const task = FindTaskBySP(caller_SP);
1950 STK_ASSERT(task != nullptr);
1951
1952 return task->GetTid();
1953 }
1954
1955 void OnSuspend(bool suspended) override
1956 {
1957 // toggle kernel state
1958 if (suspended)
1959 {
1960 if (m_kstate == KSTATE_RUNNING)
1961 {
1963 }
1964 }
1965 else
1966 {
1967 if (m_kstate == KSTATE_SUSPENDED)
1968 {
1970 }
1971 }
1972
1973 // force yield for a currently active task
1974 if (!m_task_now->IsSleeping())
1975 {
1976 m_task_now->ScheduleSleep(YIELD_TICKS);
1977 }
1978 }
1979
1980 void OnInheritWeight(TId tid, Weight weight)
1981 {
1982 STK_ASSERT(tid != TID_NONE);
1983 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1984
1985 if (weight != NO_WEIGHT)
1986 {
1987 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1988 STK_ASSERT(task != nullptr);
1989
1990 const Weight prev_weight = task->GetWeight();
1991
1992 if (prev_weight < weight)
1993 {
1994 task->SetCurrentWeight(weight);
1995 m_strategy.OnTaskWeightChange(task, prev_weight);
1996 }
1997 }
1998 }
1999
2001 {
2002 STK_ASSERT(tid != TID_NONE);
2003 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
2004
2005 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
2006 STK_ASSERT(task != nullptr);
2007
2008 const Weight prev_weight = task->GetWeight();
2009
2010 // restore to original or boost from wait objects
2011 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
2012
2013 m_strategy.OnTaskWeightChange(task, prev_weight);
2014 }
2015
2018 Timeout UpdateTasks(const Timeout elapsed_ticks)
2019 {
2020 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
2022 {
2023 UpdateSyncObjects(elapsed_ticks);
2024 }
2025
2026 if (m_request != REQ_NONE)
2027 {
2029 }
2030
2031 return UpdateTaskState(elapsed_ticks);
2032 }
2033
2034 void ProcessTaskPendingSleep(KernelTask *const task)
2035 {
2037
2038 // notify strategy that task is sleeping
2039 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2040 {
2041 m_strategy.OnTaskSleep(task);
2042 }
2043 }
2044
2045
2076 Timeout UpdateTaskState(const Timeout elapsed_ticks)
2077 {
2079
2080 for (size_t i = 0U; i < TASKS_MAX; ++i)
2081 {
2082 KernelTask *const task = &m_task_storage[i];
2083
2084 if (task->IsSleeping())
2085 {
2087 {
2088 // task is pending removal, wait until it is switched out
2089 if (task->IsPendingRemoval())
2090 {
2091 const size_t tasks_left = m_strategy.GetSize();
2092
2093 if ((task != m_task_now) ||
2094 ((tasks_left == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
2095 {
2096 RemoveTask(task);
2097 continue;
2098 }
2099 }
2100 }
2101
2102 bool just_entered_sleep = false;
2103
2104 // note: only currently scheduled task can be pending to sleep
2105 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
2106 {
2107 STK_ASSERT(elapsed_ticks == 1); // entry tick must be a single, uncoalesced tick
2108
2109 // if Wake() raced in before this entry tick ran, STATE_WAKE_PENDING is set:
2110 // deliver OnTaskSleep() below as usual, then fall through to the advance block
2111 // in this same pass instead of waiting an extra tick, so the paired OnTaskWake()
2112 // still fires on schedule.
2113 const bool wake_pending = ((task->m_state & KernelTask::STATE_WAKE_PENDING) != 0U);
2114
2116
2117 just_entered_sleep = !wake_pending;
2118 }
2119
2120 if (!just_entered_sleep && !task->IsSleepInfinite())
2121 {
2122 // advance sleep time by number of elapsed ticks (always 1 if non-Tickless)
2123 task->m_time_sleep += elapsed_ticks;
2124
2125 // deliver sleep event to the strategy
2126 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2127 {
2128 // notify strategy that the task woke up
2129 if (!task->IsSleeping())
2130 {
2131 m_strategy.OnTaskWake(task);
2132 }
2133 }
2134 }
2135 }
2136 else
2137 {
2139 {
2140 // in HRT mode we trace how long task spent in active state (doing some work)
2141 if (task->IsBusy())
2142 {
2143 task->m_hrt[0].duration += elapsed_ticks;
2144
2145 // check if deadline is missed (HRT failure)
2146 if (task->HrtIsDeadlineMissed(task->m_hrt[0].duration))
2147 {
2148 // report deadline overrun to the strategy which supports overrun recovery
2149 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
2150 {
2151 if (!m_strategy.OnTaskDeadlineMissed(task))
2152 {
2153 // report failure if it could not be recovered by the scheduling strategy
2154 task->HrtHardFailDeadline(&m_platform);
2155 }
2156 }
2157 else
2158 {
2159 task->HrtHardFailDeadline(&m_platform);
2160 }
2161 }
2162 }
2163 }
2164 }
2165
2166 // get the number of ticks the driver has to keep CPU in Idle
2168 {
2169 if ((sleep_ticks > 1) && task->IsBusy())
2170 {
2171 sleep_ticks = task->GetSleepTicks(sleep_ticks);
2172 }
2173 }
2174 }
2175
2176 return sleep_ticks;
2177 }
2178
2181 void UpdateSyncObjects(const Timeout elapsed_ticks)
2182 {
2183 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
2184
2185 while (itr != nullptr)
2186 {
2187 ISyncObject::ListEntryType *const next = itr->GetNext();
2188
2189 if (!util::DListCast::ListEntryToParent<ISyncObject>(itr)->Tick(elapsed_ticks))
2190 {
2191 m_sync_list->Unlink(itr);
2192 }
2193
2194 itr = next;
2195 }
2196 }
2197
2201 {
2202 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2203 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2205 {
2206 // process serialized AddTask request made from another active task, requesting process
2207 // is currently waiting due to SwitchToNext()
2208 if ((m_request & REQ_ADD_TASK) != 0U)
2209 {
2211
2212 for (size_t i = 0U; i < TASKS_MAX; ++i)
2213 {
2214 KernelTask *const task = &m_task_storage[i];
2215
2216 if (task->m_srt[0].add_task_req != nullptr)
2217 {
2218 AllocateAndAddNewTask(task->m_srt[0].add_task_req->user_task);
2219
2220 task->m_srt[0].add_task_req = nullptr;
2221 __stk_full_memfence();
2222 }
2223 }
2224 }
2225 }
2226 }
2227
2232 EFsmEvent FetchNextEvent(KernelTask *&next)
2233 {
2235
2236 // try getting next task for scheduling
2238
2239 // sleep-aware strategy returns nullptr if no active tasks available
2240 if (next != nullptr)
2241 {
2242 // strategy must provide active-only task
2243 STK_ASSERT(!next->IsSleeping());
2244
2245 // if was sleeping, process wake event first
2247 }
2248 // start sleeping
2249 else
2250 {
2252 {
2253 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2254 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2255 if (m_strategy.GetSize() == 0U)
2256 {
2257 next = nullptr;
2258 type = FSM_EVENT_EXIT;
2259 }
2260 }
2261 }
2262
2263 return type;
2264 }
2265
2270#ifdef _STK_UNDER_TEST
2271 virtual
2272#endif
2273 EFsmState GetNewFsmState(KernelTask *&next)
2274 {
2276 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2277 }
2278
2284 bool UpdateFsmState(Stack *&idle, Stack *&active)
2285 {
2286 KernelTask *const now = m_task_now, *next = nullptr;
2287 bool switch_context = false;
2288
2289 const EFsmState new_state = GetNewFsmState(next);
2290
2291 switch (new_state)
2292 {
2294 switch_context = StateSwitch(now, next, idle, active);
2295 m_fsm_state = new_state;
2296 break;
2297 case FSM_STATE_SLEEPING:
2298 switch_context = StateSleep(now, next, idle, active);
2299 m_fsm_state = new_state;
2300 break;
2301 case FSM_STATE_WAKING:
2302 switch_context = StateWake(now, next, idle, active);
2303 m_fsm_state = new_state;
2304 break;
2305 case FSM_STATE_EXITING:
2306 switch_context = StateExit(now, next, idle, active);
2307 m_fsm_state = new_state;
2308 break;
2309 case FSM_STATE_NONE:
2310 break; // valid intermittent non-persisting state: no-transition
2311 case FSM_STATE_MAX:
2312 default: // invalid state value
2314 break;
2315 }
2316
2317 return switch_context;
2318 }
2319
2327 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2328 {
2329 STK_ASSERT(now != nullptr);
2330 STK_ASSERT(next != nullptr);
2331
2332 bool switch_context = false;
2333
2334 // if equal: do not switch context because task did not change
2335 if (next != now)
2336 {
2337 idle = now->GetUserStackPtr();
2338 active = next->GetUserStackPtr();
2339
2340 // if stack memory is exceeded these assertions will be hit
2341 #if STK_STACK_GUARD
2342 if (now->IsBusy())
2343 {
2344 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2345 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2346 }
2347 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2348 #endif
2349
2350 m_task_now = next;
2351
2353 {
2354 if (now->m_hrt[0].done)
2355 {
2356 now->HrtOnSwitchedOut();
2357 next->HrtOnSwitchedIn();
2358 }
2359 }
2360
2361 switch_context = true;
2362 }
2363
2364 return switch_context;
2365 }
2366
2374 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2375 {
2376 STK_UNUSED(now);
2377
2378 STK_ASSERT(next != nullptr);
2379
2380 idle = &m_sleep_trap[0].stack;
2381 active = next->GetUserStackPtr();
2382
2383 // if stack memory is exceeded these assertions will be hit
2385 #if STK_STACK_GUARD
2386 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2387 #endif
2388
2389 m_task_now = next;
2390
2392 {
2393 next->HrtOnSwitchedIn();
2394 }
2395
2396 return true; // switch context
2397 }
2398
2406 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2407 {
2408 STK_UNUSED(next);
2409
2410 STK_ASSERT(now != nullptr);
2411 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
2412
2413 idle = now->GetUserStackPtr();
2414 active = &m_sleep_trap[0].stack;
2415
2417
2419 {
2420 if (!now->IsPendingRemoval())
2421 {
2422 now->HrtOnSwitchedOut();
2423 }
2424 }
2425
2426 return true; // switch context
2427 }
2428
2437 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2438 {
2439 STK_UNUSED(now);
2440 STK_UNUSED(next);
2441
2443 {
2444 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
2445 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
2446
2447 idle = nullptr;
2448 active = &m_exit_trap[0].stack;
2449
2450 m_task_now = nullptr;
2451
2452 m_platform.Stop();
2453 }
2454 else
2455 {
2456 STK_UNUSED(idle);
2457 STK_UNUSED(active);
2458 }
2459
2460 return false;
2461 }
2462
2466 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
2467
2473 {
2476 }
2477
2478#if STK_SEGGER_SYSVIEW
2483 void SendTaskTraceInfo(KernelTask *task)
2484 {
2485 STK_ASSERT(task->IsBusy());
2486
2487 const SEGGER_SYSVIEW_TASKINFO info =
2488 {
2489 .TaskID = task->GetUserStackPtr()->tid,
2490 .sName = task->GetUserTask()->GetTraceName(),
2491 .Prio = static_cast<U32>(task->GetWeight()),
2492 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
2493 .StackSize = (task->GetUserTask()->GetStackSize() * sizeof(Word))
2494 };
2495 SEGGER_SYSVIEW_SendTaskInfo(&info);
2496 }
2497#endif
2498
2499 // Kernel modes:
2500 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
2501 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
2502 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
2503 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
2504 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
2505
2506 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
2508
2509 // If hit here: Kernel mode must be assigned.
2510 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
2511
2512 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
2513 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
2514 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
2515
2516 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
2517 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
2518 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
2519
2520 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
2521 // which destroys the precise periodicity HRT depends on.
2522 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
2523 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
2524
2525 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
2526 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
2527 !TStrategy::PRIORITY_INHERITANCE_API);
2528
2533
2548
2564
2571
2572 KernelService m_service;
2573 TPlatform m_platform;
2574 TStrategy m_strategy;
2575 KernelTask *m_task_now;
2577 SleepTrapStack m_sleep_trap[1];
2580 volatile uint8_t m_request;
2583
2585 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
2590 };
2591
2593};
2594
2595} // namespace stk
2596
2597#endif /* STK_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:545
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:277
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:357
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:489
#define STK_TICKLESS_TICKS_MAX
Maximum number of kernel ticks the hardware timer may be suppressed in one tickless idle interval whe...
Definition stk_defs.h:77
#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:536
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
Definition stk_defs.h:563
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:261
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:143
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:38
static constexpr ITask * GetUserTaskFromTid(TId task_id) noexcept
Get task instance from its identifier.
Definition stk_arch.h:725
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:217
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:121
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:122
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:124
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:123
@ PERIODICITY_DEFAULT
Default periodicity (microseconds), 1 millisecond.
Definition stk_common.h:91
@ PERIODICITY_MAX
Maximum periodicity (microseconds), 99 milliseconds (note: this value is the highest working on a rea...
Definition stk_common.h:90
int64_t Ticks
Ticks value.
Definition stk_common.h:158
@ KERNEL_PANIC_BAD_MODE
Kernel is in bad/unsupported mode for the current operation.
Definition stk_common.h:68
@ KERNEL_PANIC_BAD_STATE
Kernel entered unexpected (bad) state.
Definition stk_common.h:67
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:153
static void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:183
@ SYS_TASK_ID_EXIT
Exit trap.
Definition stk_common.h:101
@ SYS_TASK_ID_SLEEP
Sleep trap.
Definition stk_common.h:100
static constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:227
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:759
static constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:222
Timeout GetInitialSleepTicks()
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:211
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:205
static constexpr T Min(T a, T b) noexcept
Compile-time minimum of two values.
Definition stk_defs.h:753
@ TRACE_EVENT_SLEEP
Task entered a sleep state.
Definition stk_common.h:112
@ TRACE_EVENT_SUSPEND
Task suspended via Suspend.
Definition stk_common.h:114
@ TRACE_EVENT_WAIT
Task suspended on a sync object.
Definition stk_common.h:113
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:81
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:80
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:82
Timeout GetInitialSleepTicks< false >()
Definition stk.h:40
static constexpr TId GetTidFromUserTask(const ITask *task) noexcept
Get task identifier from ITask instance.
Definition stk_arch.h:716
Timeout GetInitialSleepTicks< true >()
Definition stk.h:39
uint64_t Cycles
Cycles value.
Definition stk_common.h:168
Word TId
Task (thread) id.
Definition stk_common.h:148
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:173
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
Definition stk_common.h:51
@ KERNEL_SYNC
Synchronization support (see Event).
Definition stk_common.h:50
@ KERNEL_HRT
Hard Real-Time (HRT) behavior (tasks are scheduled periodically and have an execution deadline,...
Definition stk_common.h:49
@ KERNEL_STATIC
All tasks are static and can not exit.
Definition stk_common.h:47
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
Definition stk_common.h:48
static void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:396
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:214
static T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:331
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Memory-related primitives.
void OnStop() override
Called by the platform driver after a scheduler stop (all tasks have exited).
Definition stk.h:1716
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2284
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1434
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1520
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:1878
void OnTaskSleepCancel(TId task_id)
Definition stk.h:1864
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1361
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:1565
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:2532
~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:1743
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:1900
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:1955
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1156
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2273
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel when it is not started.
Definition stk.h:1131
StackMemoryWrapper< STACK_SIZE_MIN > ExitTrapStackMemory
Stack memory wrapper type for the exit trap.
Definition stk.h:102
void OnRestoreWeight(TId tid, ISyncObject *sobj)
Definition stk.h:2000
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:1651
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:2374
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:1586
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1400
static constexpr bool IsHrtMode()
Definition stk.h:2502
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:1067
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:2570
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1375
StackMemoryWrapper<((32U))> SleepTrapStackMemory
Stack memory wrapper type for the sleep trap.
Definition stk.h:96
size_t EnumerateKernelTasks(ArrayView< IKernelTask * > tasks) override
Enumerate kernel tasks.
Definition stk.h:1249
static constexpr bool IsSyncMode()
Definition stk.h:2503
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance.
Definition stk.h:1544
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1393
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:1980
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1229
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:1796
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1301
static constexpr bool IsTicklessMode()
Definition stk.h:2504
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:1626
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1474
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1345
ERequest
Bitmask flags for pending inter-task requests that must be processed by the kernel on the next tick (...
Definition stk.h:109
bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Exits from scheduling.
Definition stk.h:2437
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1336
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1491
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:1791
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:1030
TPlatform m_platform
Platform driver (SysTick, PendSV, context switch implementation).
Definition stk.h:2573
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:1506
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:1947
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1273
void ProcessTaskPendingSleep(KernelTask *const task)
Definition stk.h:2034
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:2018
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:2472
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:2466
static constexpr bool IsDynamicMode()
Definition stk.h:2501
bool OnForceContextSwitch(TId id, Stack *&idle, Stack *&active)
Called when task state change forces a context switch (Sleep, SleepUntil, Wait).
Definition stk.h:1770
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1341
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2327
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:1106
Kernel()
Construct the kernel with all storage zero-initialized, m_request cleared to REQ_NONE,...
Definition stk.h:997
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2200
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:2406
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, deliver sleep/wake notifications, advance sleep timers,...
Definition stk.h:2076
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:2181
static constexpr bool IsStaticMode()
Definition stk.h:2500
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1328
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:1825
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1184
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2232
Internal per-slot kernel descriptor that wraps a user ITask instance.
Definition stk.h:126
Weight GetCurrentWeight() const override
Get current (run-time) scheduling weight.
Definition stk.h:269
KernelTask()
Construct a free (unbound) task slot. All fields set to zero/null.
Definition stk.h:158
void ScheduleSleep(Timeout ticks)
Put the task into a sleeping state for the specified number of ticks.
Definition stk.h:750
Timeout GetSleepTicks(Timeout sleep_ticks)
Definition stk.h:356
TId GetTid() const
Get task identifier.
Definition stk.h:196
void HrtOnSwitchedOut()
Called when task is switched out from the scheduling process.
Definition stk.h:693
EStateFlags
Bitmask of transient state flags. Set by the task or the kernel and consumed (cleared) during UpdateT...
Definition stk.h:134
@ STATE_REMOVE_PENDING
Task returned from its Run function; slot will be freed on the next tick (KERNEL_DYNAMIC only).
Definition stk.h:136
@ STATE_WAKE_PENDING
Task wake is pending (see Wake).
Definition stk.h:138
@ STATE_SLEEP_PENDING
Task called Sleep/SleepUntil/Yield; strategy's OnTaskSleep() will be invoked on the next tick (sleep-...
Definition stk.h:137
@ STATE_NONE
No pending state flags.
Definition stk.h:135
Timeout GetHrtPeriodicity() const override
Get HRT scheduling periodicity.
Definition stk.h:289
friend class Kernel
Definition stk.h:127
bool HrtIsDeadlineMissed(Timeout duration) const
Check if deadline missed.
Definition stk.h:736
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:786
void ScheduleRemoval()
Schedule the removal of the task from the kernel on next tick.
Definition stk.h:608
Stack m_stack
Stack descriptor (SP register value + access mode + optional tid).
Definition stk.h:783
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:556
~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:788
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:713
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:668
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:784
bool IsSleepInfinite() const
Check whether this task is currently sleeping infinitely.
Definition stk.h:191
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:782
Timeout GetHrtRelativeDeadline() const override
Get remaining HRT deadline (ticks left before the deadline expires).
Definition stk.h:337
void SetCurrentWeight(Weight weight) override
Update the run-time scheduling weight (weighted strategies only).
Definition stk.h:219
void BusyWaitWhileSleeping(Kernel *kernel) const
Block further execution of the task's context while in sleeping state.
Definition stk.h:767
Stack GetUserStack() const override
Get stack descriptor for this task slot.
Definition stk.h:176
bool IsBusy() const
Check whether this slot is bound to a user task.
Definition stk.h:181
bool IsSleeping() const override
Check whether this task is currently sleeping (waiting for a tick or a wake event).
Definition stk.h:186
Stack * GetUserStackPtr()
Get pointer to user Stack.
Definition stk.h:780
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:787
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:727
void Wake() override
Wake this task on the next scheduling tick.
Definition stk.h:202
Weight GetWeight() const override
Get static scheduling weight from the user task.
Definition stk.h:230
volatile Timeout m_time_sleep
Sleep countdown: negative while sleeping (absolute value = ticks remaining), zero when awake.
Definition stk.h:785
bool IsPendingRemoval() const
Check if task is pending removal.
Definition stk.h:625
Timeout GetHrtDeadline() const override
Get absolute HRT deadline (ticks elapsed since task was activated).
Definition stk.h:312
void Unbind()
Reset this slot to the free (unbound) state, clearing all scheduling metadata.
Definition stk.h:583
void HrtOnSwitchedIn()
Called when task is switched into the scheduling process.
Definition stk.h:688
bool IsMemoryOfSP(Word SP) const
Check if Stack Pointer (SP) belongs to this task.
Definition stk.h:630
ITask * GetUserTask() override
Get bound user task.
Definition stk.h:171
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:789
Payload for an in-flight AddTask() request issued by a running task.
Definition stk.h:150
ITask * user_task
User task to add. Must remain valid for the lifetime of its kernel slot.
Definition stk.h:151
Per-task soft real-time (SRT) metadata.
Definition stk.h:401
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:407
AddTaskRequest * add_task_req
Definition stk.h:417
Per-task Hard Real-Time (HRT) scheduling metadata.
Definition stk.h:425
void Clear()
Clear all fields, ready for slot re-use or re-activation.
Definition stk.h:431
volatile bool done
Set to true when the task signals work completion (via Yield() or on exit). Triggers HrtOnSwitchedOut...
Definition stk.h:442
Timeout deadline
Maximum allowed active duration in ticks (relative to switch-in). Exceeding this triggers OnDeadlineM...
Definition stk.h:440
Timeout periodicity
Activation period in ticks: the task is re-activated every this many ticks.
Definition stk.h:439
Timeout duration
Ticks spent in the active (non-sleeping) state in the current period. Incremented by UpdateTaskState(...
Definition stk.h:441
Concrete implementation of IWaitObject, embedded in each KernelTask slot.
Definition stk.h:452
bool IsWaiting() const
Check if busy with waiting.
Definition stk.h:484
Timeout m_time_wait
Ticks remaining until timeout. Decremented each tick; WAIT_INFINITE means no timeout.
Definition stk.h:549
void Wake(bool timeout) override
Wake the waiting task (called by ISyncObject when it signals).
Definition stk.h:491
~WaitObject()=default
Destructor.
bool Tick(Timeout elapsed_ticks) override
Advance the timeout countdown by one tick.
Definition stk.h:510
bool IsTimeout() const override
Check whether the wait expired due to timeout.
Definition stk.h:479
void SetupWait(ISyncObject *sync_obj, Timeout timeout)
Configure and arm this wait object for a new wait operation.
Definition stk.h:535
TId GetTid() const override
Get the TId of the task that owns this wait object.
Definition stk.h:474
volatile bool m_timeout
true if the wait expired due to timeout rather than a Wake() signal.
Definition stk.h:548
ISyncObject * m_sync_obj
Sync object this wait is registered with, or NULL when not waiting.
Definition stk.h:547
KernelTask * m_task
Back-pointer to the owning KernelTask. Set once at construction; never changes.
Definition stk.h:546
Payload stored in the sync object's kernel-side list entry while a task is waiting.
Definition stk.h:467
ISyncObject * sync_obj
Sync object whose Tick() will be called each kernel tick.
Definition stk.h:468
KernelService()
Construct an uninitialized service instance (m_platform = null, m_ticks = 0).
Definition stk.h:953
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:908
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:869
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:981
void Wake(ISyncObject *sobj, bool all) override
Wake one or all tasks currently waiting on a synchronization object.
Definition stk.h:889
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:812
friend class Kernel
Definition stk.h:801
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:829
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:980
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:806
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:861
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:921
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:845
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:941
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:933
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:810
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:808
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:814
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:804
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:876
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:974
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:966
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2542
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:2543
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:2546
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2545
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2558
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:2562
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:2559
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2561
RAII instance that enters the critical section on construction and exits it on destruction.
Definition stk_arch.h:494
Lightweight, non-owning view over a contiguous sequence of elements.
Definition stk_common.h:254
size_t GetSize() const
Get number of elements in the view.
Definition stk_common.h:294
Stack descriptor.
Definition stk_common.h:392
uint32_t access_mode
Bitfield with hardware access mode of the task (see EAccessMode).
Definition stk_common.h:394
TId tid
Task id (see STK_SEGGER_SYSVIEW, STK_MPU_STACK_GUARD).
Definition stk_common.h:405
Interface for a stack memory region.
Definition stk_common.h:413
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:462
Synchronization object interface.
Definition stk_common.h:564
virtual void WakeAll()=0
Wake all tasks currently in the wait list.
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:577
virtual void WakeOne()=0
Wake the first task in the wait list (FIFO order).
DLHeadType ListHeadType
List head type for ISyncObject elements.
Definition stk_common.h:572
static void AddWaitObject(IWaitObject::ListHeadType &wlist, IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:583
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:333
Interface for mutex synchronization primitive.
Definition stk_common.h:697
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:755
virtual EAccessMode GetAccessMode() const =0
Get pointer to the stack memory.
virtual void OnExit()
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
Definition stk_common.h:852
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:885
Interface for a platform driver.
Definition stk_common.h:978
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
Definition stk_common.h:986
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 IWaitObject::ListHeadType & GetWaitList(ISyncObject *sobj)
IWaitObject::GetWaitList() access helper.
static constexpr size_t Value
Definition stk_defs.h:675
Adapts an externally-owned stack memory array to the IStackMemory interface.
Definition stk_helper.h:189
StackMemoryDef< _StackSize >::Type MemoryType
Definition stk_helper.h:194
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.