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 {
138 };
139
140 public:
149 {
151 };
152
158 m_srt(), m_hrt(), m_rt_weight()
159 {
160 // bind to wait object
162 {
163 m_wait_obj->m_task = this;
164 }
165 }
166
170 ITask *GetUserTask() override { return m_user; }
171
175 Stack GetUserStack() const override { return m_stack;}
176
180 bool IsBusy() const { return (m_user != nullptr); }
181
185 __stk_forceinline bool IsSleeping() const override { return (m_time_sleep < 0); }
186
190 TId GetTid() const { return GetTidFromUserTask(m_user); }
191
196 void Wake() override
197 {
199
200 // wakeup on a next cycle
201 m_time_sleep = -1;
202 }
203
207 void SetCurrentWeight(Weight weight) override
208 {
209 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
210 {
211 m_rt_weight[0] = weight;
212 }
213 }
214
218 Weight GetWeight() const override
219 {
220 Weight static_weight;
221
222 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
223 {
224 if (m_rt_weight[0] != NO_WEIGHT)
225 {
226 static_weight = m_rt_weight[0];
227 }
228 else
229 {
230 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
231 {
232 static_weight = m_user->GetWeight();
233 }
234 else
235 {
236 static_weight = DEFAULT_WEIGHT;
237 }
238 }
239 }
240 else if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
241 {
242 static_weight = m_user->GetWeight();
243 }
244 else
245 {
246 static_weight = DEFAULT_WEIGHT;
247 }
248
249 return static_weight;
250 }
251
257 Weight GetCurrentWeight() const override
258 {
259 Weight cur_weight;
260
261 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
262 {
263 cur_weight = m_rt_weight[0];
264 }
265 else
266 {
267 cur_weight = DEFAULT_WEIGHT;
268 }
269
270 return cur_weight;
271 }
272
277 Timeout GetHrtPeriodicity() const override
278 {
280
281 Timeout to;
282
284 {
285 to = m_hrt[0].periodicity;
286 }
287 else
288 {
289 to = 0;
290 }
291
292 return to;
293 }
294
300 Timeout GetHrtDeadline() const override
301 {
303
304 Timeout deadline;
305
307 {
308 deadline = m_hrt[0].deadline;
309 }
310 else
311 {
312 deadline = 0;
313 }
314
315 return deadline;
316 }
317
326 {
329
330 Timeout relative_deadline;
331
333 {
334 relative_deadline = (m_hrt[0].deadline - m_hrt[0].duration);
335 }
336 else
337 {
338 relative_deadline = 0;
339 }
340
341 return relative_deadline;
342 }
343
345 {
346 // note: task sleep time is negative
348
350 {
351 // likely task is sleeping during sync operation (see Wait)
352 if (m_wait_obj->IsWaiting())
353 {
354 // note: sync wait time is positive
355 task_sleep = m_wait_obj->m_time_wait;
356
357 // we shall account for only valid time (when task is waiting during sync operation)
358 if (task_sleep > NO_WAIT)
359 {
360 sleep_ticks = Min(sleep_ticks, task_sleep);
361 }
362 }
363 else
364 {
365 sleep_ticks = Min(sleep_ticks, task_sleep);
366 }
367 }
368 else
369 {
370 sleep_ticks = Min(sleep_ticks, task_sleep);
371 }
372
373 // clamp to [1, STK_TICKLESS_TICKS_MAX] range
374 return Max<Timeout>(1, sleep_ticks);
375 }
376
377 protected:
382
388 struct SrtInfo
389 {
391 {}
392
395 void Clear()
396 {
397 add_task_req = nullptr;
398 }
399
406 };
407
412 struct HrtInfo
413 {
414 HrtInfo() : periodicity(0), deadline(0), duration(0), done(false)
415 {}
416
419 void Clear()
420 {
421 periodicity = 0;
422 deadline = 0;
423 duration = 0;
424 done = false;
425 }
426
430 volatile bool done;
431 };
432
439 struct WaitObject final : public IWaitObject
440 {
441 explicit WaitObject() : m_task(nullptr), m_sync_obj(nullptr), m_timeout(false), m_time_wait(0)
442 {}
443
448
455 {
457 };
458
462 TId GetTid() const override { return m_task->GetTid(); }
463
467 bool IsTimeout() const override { return m_timeout; }
468
472 bool IsWaiting() const { return (m_sync_obj != nullptr); }
473
479 void Wake(bool timeout) override
480 {
482
483 m_timeout = timeout;
484 m_time_wait = 0;
485
486 m_sync_obj->RemoveWaitObject(this);
487 m_sync_obj = nullptr;
488
489 return m_task->Wake();
490 }
491
498 bool Tick(Timeout elapsed_ticks) override
499 {
501 {
502 if (!m_timeout)
503 {
504 m_time_wait -= elapsed_ticks;
505
506 if (m_time_wait <= 0)
507 {
508 m_timeout = true;
509 }
510 }
511 }
512
513 return !m_timeout;
514 }
515
523 void SetupWait(ISyncObject *sync_obj, Timeout timeout)
524 {
526
527 m_sync_obj = sync_obj;
528 m_time_wait = timeout;
529 m_timeout = false;
530
531 sync_obj->AddWaitObject(this);
532 }
533
536 volatile bool m_timeout;
538 };
539
544 void Bind(TPlatform *platform, ITask *user_task)
545 {
546 // set access mode for this stack
547 m_stack.access_mode = user_task->GetAccessMode();
548
549 // set task id for tracking purpose
550 #if STK_STACK_NEEDS_TASK_ID
551 m_stack.tid = GetTid();
552 #endif
553
554 // init stack of the user task
555 platform->InitStack(STACK_USER_TASK, &m_stack, user_task, user_task);
556
557 // bind user task
558 m_user = user_task;
559
560 // initialize current weight to NO_WEIGHT for priority inheritance mechanism
561 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
562 {
564 }
565 }
566
570 void Unbind()
571 {
573 {
574 // should be freed from waiting on task exit
575 STK_ASSERT(!m_wait_obj->IsWaiting());
576 }
577
578 m_user = nullptr;
579 m_stack = {};
581 m_time_sleep = 0;
582
584 {
585 m_hrt[0].Clear();
586 }
587 else
588 {
589 m_srt->Clear();
590 }
591 }
592
596 {
597 // make this task sleeping to switch it out from scheduling process
599
600 // mark it as done HRT task
602 {
604 }
605
606 // mark it as pending for removal
608 }
609
612 bool IsPendingRemoval() const { return ((m_state & STATE_REMOVE_PENDING) != 0U); }
613
617 bool IsMemoryOfSP(Word SP) const
618 {
619 bool is_match = false;
620
621 const Word start = hw::PtrToWord(m_user->GetStack());
622 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
623
624 if ((SP >= start) && (SP <= end))
625 {
626 is_match = true;
627 }
628 #if STK_TZ_SECURE // lookup Secure memory region too when on a Secure side
629 else
630 {
631 IStackMemory *const secure_mem = m_user->GetSecureStackMemory();
632
633 if (secure_mem != nullptr)
634 {
635 const Word s_start = hw::PtrToWord(secure_mem->GetStack());
636 const Word s_end = s_start + (secure_mem->GetStackSize() * sizeof(Word));
637
638 if ((SP >= s_start) && (SP <= s_end))
639 {
640 is_match = true;
641 }
642 }
643 }
644 #endif
645
646 return is_match;
647 }
648
655 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
656 {
657 STK_ASSERT(periodicity_tc > 0);
658 STK_ASSERT(deadline_tc > 0);
659 STK_ASSERT(start_delay_tc >= 0);
660 STK_ASSERT(periodicity_tc < INT32_MAX);
661 STK_ASSERT(deadline_tc < INT32_MAX);
662
663 m_hrt[0].periodicity = periodicity_tc;
664 m_hrt[0].deadline = deadline_tc;
665
666 if (start_delay_tc > 0)
667 {
668 ScheduleSleep(start_delay_tc);
669 }
670 }
671
676
681 {
682 const Timeout duration = m_hrt[0].duration;
683
684 STK_ASSERT(duration >= 0);
685
686 const Timeout sleep = m_hrt[0].periodicity - duration;
687 if (sleep > 0)
688 {
689 ScheduleSleep(sleep);
690 }
691
692 m_hrt[0].duration = 0;
693 m_hrt[0].done = false;
694 }
695
701 {
702 const Timeout duration = m_hrt[0].duration;
703
704 STK_ASSERT(duration >= 0);
706
707 m_user->OnDeadlineMissed(duration);
708 platform->ProcessHardFault();
709 }
710
715 {
716 m_hrt[0].done = true;
717 __stk_full_memfence();
718 }
719
723 bool HrtIsDeadlineMissed(Timeout duration) const
724 {
725 return (duration > m_hrt[0].deadline);
726 }
727
738 {
739 STK_ASSERT(ticks > 0);
740
741 // set state first as kernel checks it when task IsSleeping
742 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
743 {
744 if (!IsSleeping())
745 {
747 }
748 }
749
750 m_time_sleep = -ticks;
751 __stk_full_memfence();
752 }
753
757 {
758 while (IsSleeping())
759 {
760 __stk_relax_cpu();
761 }
762 }
763
768
771 volatile uint32_t m_state;
777 };
778
786 class KernelService final : public IKernelService
787 {
788 friend class Kernel;
789
790 public:
791 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
792
793 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
794
795 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
796
797 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
798
799 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
800
801 void Delay(Timeout ticks) override
802 {
804 STK_ASSERT(ticks >= 0);
805
806 Ticks now = GetTicks();
807 const Ticks deadline = now + ticks;
808 STK_ASSERT(deadline >= now);
809
810 for (; now < deadline; now = GetTicks())
811 {
812 __stk_relax_cpu();
813 }
814 }
815
816 void Sleep(Timeout ticks) override
817 {
819 STK_ASSERT(ticks >= 0);
820
822 {
823 m_kernel->m_platform.Sleep(ticks);
824 }
825 else
826 {
827 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
828 STK_ASSERT(false);
829 }
830 }
831
832 bool SleepUntil(Ticks timestamp) override
833 {
835
837 {
838 return m_kernel->m_platform.SleepUntil(timestamp);
839 }
840 else
841 {
842 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
843 STK_ASSERT(false);
844 return false;
845 }
846 }
847
848 void SleepCancel(TId task_id) override
849 {
851 {
852 m_kernel->OnTaskSleepCancel(task_id);
853 }
854 }
855
856 void SwitchToNext() override
857 {
859
860 m_kernel->m_platform.SwitchToNext();
861 }
862
863 EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
864 {
866 {
867 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
868 }
869 else
870 {
871 STK_ASSERT(false);
872 return WAIT_RESULT_FAIL;
873 }
874 }
875
876 void Wake(ISyncObject *sobj, bool all)
877 {
879 {
880 if (all)
881 {
883 }
884 else
885 {
887 }
888 }
889 else
890 {
891 STK_ASSERT(false);
892 }
893 }
894
895 Timeout Suspend() override
896 {
898 {
899 return m_kernel->m_platform.Suspend();
900 }
901 else
902 {
903 STK_ASSERT(false);
904 return 0;
905 }
906 }
907
908 void Resume(Timeout elapsed_ticks) override
909 {
911 {
912 return m_kernel->m_platform.Resume(elapsed_ticks);
913 }
914 else
915 {
916 STK_ASSERT(false);
917 }
918 }
919
920 void InheritWeight(TId tid, Weight weight) override
921 {
922 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
923 {
924 m_kernel->OnInheritWeight(tid, weight);
925 }
926 }
927
928 void RestoreWeight(TId tid, ISyncObject *sobj) override
929 {
930 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
931 {
932 m_kernel->OnRestoreWeight(tid, sobj);
933 }
934 }
935
936 private:
940 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
941 {}
942
947
953 void Initialize(Kernel *kernel)
954 {
955 m_kernel = kernel;
956 }
957
961 void IncrementTicks(Ticks advance)
962 {
963 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
965 }
966
968 volatile Ticks m_ticks;
969 };
970
971public:
974 static constexpr size_t TASKS_MAX = TSize;
975
986 {
987 #ifdef _DEBUG
988 // TPlatform must inherit IPlatform
989 IPlatform *platform = &m_platform;
990 STK_UNUSED(platform);
991
992 // TStrategy must inherit ITaskSwitchStrategy
993 ITaskSwitchStrategy *strategy = &m_strategy;
994 STK_UNUSED(strategy);
995 #endif
996
997 #if !STK_TICKLESS_IDLE
998 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
999 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
1000 #endif
1001 }
1002
1007
1017 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
1018 {
1019 STK_ASSERT(resolution_us != 0);
1020 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
1022
1023 // reinitialize key state variables
1024 m_task_now = nullptr;
1027
1028 // exit trap is required only for KERNEL_DYNAMIC mode
1029 Stack *exit_trap;
1031 {
1032 exit_trap = &m_exit_trap[0].stack;
1033 }
1034 else
1035 {
1036 exit_trap = nullptr;
1037 }
1038
1039 m_service.Initialize(this);
1040 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
1041
1042 // now ready to Start()
1044 }
1045
1054 __stk_attr_noinline void AddTask(ITask *user_task) override
1055 {
1057 {
1058 STK_ASSERT(user_task != nullptr);
1060
1061 // when started the operation must be serialized by switching out from processing until
1062 // kernel processes this request
1063 if (IsStarted())
1064 {
1066 {
1067 RequestAddTask(user_task);
1068 }
1069 else
1070 {
1071 STK_ASSERT(false);
1072 }
1073 }
1074 else
1075 {
1076 AllocateAndAddNewTask(user_task);
1077 }
1078 }
1079 else
1080 {
1081 STK_ASSERT(false);
1082 }
1083 }
1084
1093 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1094 Timeout start_delay_tc) override
1095 {
1097 {
1098 STK_ASSERT(user_task != nullptr);
1101
1102 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1103 }
1104 else
1105 {
1106 STK_ASSERT(false);
1107 }
1108 }
1109
1118 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1119 {
1121 {
1122 STK_ASSERT(user_task != nullptr);
1124
1125 KernelTask *const task = FindTaskByUserTask(user_task);
1126 if (task != nullptr)
1127 {
1128 RemoveTask(task);
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 {
1146 {
1147 STK_ASSERT(user_task != nullptr);
1149
1151
1152 KernelTask *const task = FindTaskByUserTask(user_task);
1153 if (task != nullptr)
1154 {
1155 task->ScheduleRemoval();
1156 }
1157 }
1158 else
1159 {
1160 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1161 STK_ASSERT(false);
1162 }
1163 }
1164
1171 void SuspendTask(ITask *user_task, bool &suspended) override
1172 {
1173 STK_ASSERT(user_task != nullptr);
1174
1175 bool self = false;
1176
1177 // avoid race with OnTick
1178 {
1180
1181 KernelTask *const task = FindTaskByUserTask(user_task);
1182 STK_ASSERT(task != nullptr);
1183
1184 // only suspend if the task is currently awake: if it is already sleeping
1185 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1186 // that would corrupt the original sleep state and, for sync-object waits,
1187 // would interfere with WaitObject::Tick()
1188 suspended = !task->IsSleeping();
1189 if (suspended == true)
1190 {
1191 task->ScheduleSleep(WAIT_INFINITE);
1192
1193 // check if suspending self
1194 self = (task == m_task_now);
1195 }
1196 }
1197
1198 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1199 if (self)
1200 {
1201 m_task_now->BusyWaitWhileSleeping();
1202 }
1203 }
1204
1208 void ResumeTask(ITask *user_task) override
1209 {
1210 STK_ASSERT(user_task != nullptr);
1211
1212 // avoid race with OnTick
1214
1215 KernelTask *const task = FindTaskByUserTask(user_task);
1216 STK_ASSERT(task != nullptr);
1217
1218 if (task->IsSleeping())
1219 {
1220 task->Wake();
1221 }
1222 }
1223
1229 {
1230 size_t count = 0U;
1231 const size_t limit = Min(tasks.GetSize(), TASKS_MAX);
1232
1233 // avoid race with OnTick
1235
1236 for (size_t i = 0U; i < limit; ++i)
1237 {
1238 KernelTask *const task = &m_task_storage[i];
1239 if (task->IsBusy())
1240 {
1241 tasks[count++] = task;
1242 }
1243 }
1244
1245 return count;
1246 }
1247
1252 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1253 {
1254 size_t count = 0U;
1255 const size_t limit = Min(user_tasks.GetSize(), TASKS_MAX);
1256
1257 // avoid race with OnTick
1259
1260 for (size_t i = 0U; i < limit; ++i)
1261 {
1262 KernelTask *const task = &m_task_storage[i];
1263 if (task->IsBusy())
1264 {
1265 user_tasks[count++] = task->GetUserTask();
1266 }
1267 }
1268
1269 return count;
1270 }
1271
1281 {
1283
1284 // stacks of the traps must be re-initilized on every subsequent Start
1285 InitTraps();
1286
1287 // start tracing
1288 #if STK_SEGGER_SYSVIEW
1289 SEGGER_SYSVIEW_Start();
1290 for (size_t i = 0U; i < TASKS_MAX; ++i)
1291 {
1292 KernelTask *task = &m_task_storage[i];
1293 if (task->IsBusy())
1294 {
1295 SendTaskTraceInfo(task);
1296 }
1297 }
1298 #endif
1299
1300 m_platform.Start();
1301 }
1302
1307 bool IsStarted() const
1308 {
1309 return (m_task_now != nullptr);
1310 }
1311
1315 IPlatform *GetPlatform() override { return &m_platform; }
1316
1321
1324 EKernelState GetState() const override { return m_kstate; }
1325
1326protected:
1340
1353
1360 static constexpr Timeout YIELD_TICKS = 2;
1361
1365 {
1366 return (state > FSM_STATE_NONE) &&
1367 (state < FSM_STATE_MAX);
1368 }
1369
1373 {
1374 // init stack for a Sleep trap
1375 {
1376 SleepTrapStack &sleep = m_sleep_trap[0];
1377
1378 SleepTrapStackMemory wrapper(&sleep.memory);
1379 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1380 #if STK_STACK_NEEDS_TASK_ID
1381 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1382 #endif
1383
1384 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1385 }
1386
1387 // init stack for an Exit trap
1389 {
1390 ExitTrapStack &exit = m_exit_trap[0];
1391
1392 ExitTrapStackMemory wrapper(&exit.memory);
1393 exit.stack.access_mode = ACCESS_PRIVILEGED;
1394 #if STK_STACK_NEEDS_TASK_ID
1395 exit.stack.tid = SYS_TASK_ID_EXIT;
1396 #endif
1397
1398 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1399 }
1400 }
1401
1406 KernelTask *AllocateNewTask(ITask *user_task)
1407 {
1408 // look for a free kernel task
1409 KernelTask *new_task = nullptr;
1410 for (size_t i = 0U; i < TASKS_MAX; ++i)
1411 {
1412 KernelTask *const task = &m_task_storage[i];
1413 if (task->IsBusy())
1414 {
1415 // avoid task collision
1416 STK_ASSERT(task->m_user != user_task);
1417
1418 // avoid stack collision
1419 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1420 }
1421 else
1422 if (new_task == nullptr)
1423 {
1424 new_task = task;
1425 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1426 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1427 #endif
1428 }
1429 else
1430 {
1431 // noop, continue to the next slot
1432 }
1433 }
1434
1435 // if nullptr - exceeded max supported kernel task count, application design failure
1436 STK_ASSERT(new_task != nullptr);
1437
1438 new_task->Bind(&m_platform, user_task);
1439
1440 return new_task;
1441 }
1442
1446 void AddKernelTask(KernelTask *task)
1447 {
1448 #if STK_SEGGER_SYSVIEW
1449 // start tracing new task
1450 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1451 if (IsStarted())
1452 SendTaskTraceInfo(task);
1453 #endif
1454
1455 m_strategy.AddTask(task);
1456 }
1457
1462 {
1463 KernelTask *const task = AllocateNewTask(user_task);
1464 STK_ASSERT(task != nullptr);
1465
1466 AddKernelTask(task);
1467 }
1468
1476 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1477 {
1478 KernelTask *const task = AllocateNewTask(user_task);
1479 STK_ASSERT(task != nullptr);
1480
1481 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1482
1483 AddKernelTask(task);
1484 }
1485
1491 {
1492 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1493 STK_ASSERT(caller != nullptr);
1494
1495 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1496 caller->m_srt[0].add_task_req = &req;
1497
1498 // notify kernel
1500
1501 // switch out and wait for completion (due to context switch request could be processed here)
1502 if (caller->m_srt[0].add_task_req != nullptr)
1503 {
1504 m_service.SwitchToNext();
1505 }
1506
1507 STK_ASSERT(caller->m_srt[0].add_task_req == nullptr);
1508 }
1509
1514 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
1515 {
1516 KernelTask *found_task = nullptr;
1517
1518 for (size_t i = 0U; i < TASKS_MAX; ++i)
1519 {
1520 KernelTask *const task = &m_task_storage[i];
1521 if (task->GetUserTask() == user_task)
1522 {
1523 found_task = task;
1524 break;
1525 }
1526 }
1527
1528 return found_task;
1529 }
1530
1535 KernelTask *FindTaskByStack(const Stack *stack)
1536 {
1537 KernelTask *found_task = nullptr;
1538
1539 for (size_t i = 0U; i < TASKS_MAX; ++i)
1540 {
1541 KernelTask *const task = &m_task_storage[i];
1542 if (task->GetUserStackPtr() == stack)
1543 {
1544 found_task = task;
1545 break;
1546 }
1547 }
1548
1549 return found_task;
1550 }
1551
1557 {
1558 STK_ASSERT(m_task_now != nullptr);
1559
1560 KernelTask *found_task = nullptr;
1561
1562 if (m_task_now->IsMemoryOfSP(SP))
1563 {
1564 found_task = m_task_now;
1565 }
1566 else
1567 {
1568 for (size_t i = 0U; i < TASKS_MAX; ++i)
1569 {
1570 KernelTask *const task = &m_task_storage[i];
1571
1572 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
1574 {
1575 if (!task->IsBusy())
1576 {
1577 continue;
1578 }
1579 }
1580
1581 if (task->IsMemoryOfSP(SP))
1582 {
1583 found_task = task;
1584 break;
1585 }
1586 }
1587 }
1588
1589 return found_task;
1590 }
1591
1596 void RemoveTask(KernelTask *task)
1597 {
1598 STK_ASSERT(task != nullptr);
1599
1600 #if STK_SEGGER_SYSVIEW
1601 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
1602 #endif
1603
1604 // notify task about pending exit
1605 task->GetUserTask()->OnExit();
1606
1607 m_strategy.RemoveTask(task);
1608 task->Unbind();
1609 }
1610
1621 __stk_attr_noinline void OnStart(Stack *&active) override
1622 {
1623 STK_ASSERT(m_strategy.GetSize() != 0);
1624
1625 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
1626 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
1627 {
1628 for (size_t i = 0U; i < TASKS_MAX; ++i)
1629 {
1630 KernelTask *const task = &m_task_storage[i];
1631
1632 if (task->IsSleeping())
1633 {
1634 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
1635 {
1636 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
1637
1638 // notify strategy that task is sleeping
1639 m_strategy.OnTaskSleep(task);
1640 }
1641 }
1642 }
1643 }
1644
1645 // get initial state and first task
1646 {
1648
1649 KernelTask *next = nullptr;
1651
1652 // expecting only SLEEPING or SWITCHING states
1654
1656 {
1657 m_task_now = next;
1658 active = next->GetUserStackPtr();
1659
1661 {
1662 next->HrtOnSwitchedIn();
1663 }
1664 }
1665 else
1667 {
1669 active = &m_sleep_trap[0].stack;
1670 }
1671 else
1672 {
1673 // unexpected state
1675 }
1676 }
1677
1678 // is in running state
1680
1681 #if STK_SEGGER_SYSVIEW
1682 SEGGER_SYSVIEW_OnTaskStartExec(m_task_now->tid);
1683 #endif
1684 }
1685
1692 {
1694 {
1696
1697 // is in stopped state, i.e. is ready to Start() again
1699 }
1700 }
1701
1718 bool OnTick(Stack *&idle, Stack *&active
1719 #if STK_TICKLESS_IDLE
1720 , Timeout &ticks
1721 #endif
1722 ) override
1723 {
1724 #if !STK_TICKLESS_IDLE
1725 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
1726 enum { ticks = 1 };
1727 #endif
1728
1729 // advance internal timestamp
1730 m_service.IncrementTicks(ticks);
1731
1732 // consume elapsed and update to ticks to sleep
1733 #if STK_TICKLESS_IDLE
1734 ticks = (
1735 #else
1736 // notify compiler that we ignore a return value of UpdateTasks
1737 STK_UNUSED(
1738 #endif
1739 UpdateTasks(ticks));
1740
1741 // decide on a context switch
1742 return UpdateFsmState(idle, active);
1743 }
1744
1745 void OnTaskSwitch(Word caller_SP) override
1746 {
1747 OnTaskSleep(caller_SP, YIELD_TICKS);
1748 }
1749
1750 void OnTaskSleep(Word caller_SP, Timeout ticks) override
1751 {
1752 KernelTask *const task = FindTaskBySP(caller_SP);
1753 STK_ASSERT(task != nullptr);
1754
1755 // make change to HRT state and sleep time atomic
1756 {
1758
1760 {
1761 task->HrtOnWorkCompleted();
1762 }
1763
1764 if (ticks > 0)
1765 {
1766 task->ScheduleSleep(ticks);
1767 }
1768 }
1769
1770 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1771 task->BusyWaitWhileSleeping();
1772 }
1773
1774 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
1775 {
1776 KernelTask *const task = FindTaskBySP(caller_SP);
1777 STK_ASSERT(task != nullptr);
1778
1779 bool result = true;
1780
1781 // make change to HRT state and sleep time atomic
1782 {
1784
1785 // calculate signed delta (handles wrap-around correctly)
1786 const Ticks delta = timestamp - m_service.m_ticks;
1787
1788 if (delta > 0)
1789 {
1790 const Ticks infinite_ticks = WAIT_INFINITE;
1791 task->ScheduleSleep(static_cast<Timeout>(Min(delta, infinite_ticks)));
1792 }
1793 else
1794 {
1795 result = false; // deadline already hit or passed
1796 }
1797 }
1798
1799 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1800 task->BusyWaitWhileSleeping();
1801 return result;
1802 }
1803
1805 {
1806 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(task_id));
1807 if (task != nullptr)
1808 {
1810
1811 if (task->IsSleeping())
1812 {
1813 task->Wake();
1814 }
1815 }
1816 }
1817
1818 void OnTaskExit(Stack *stack) override
1819 {
1821 {
1822 KernelTask *const task = FindTaskByStack(stack);
1823 STK_ASSERT(task != nullptr);
1824
1825 // notify kernel to execute removal
1826 task->ScheduleRemoval();
1827 }
1828 else
1829 {
1830 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
1832 }
1833 }
1834
1835 EWaitResult OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
1836 {
1838 {
1839 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
1840 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
1841 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
1842 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
1843
1844 KernelTask *const task = FindTaskBySP(caller_SP);
1845 STK_ASSERT(task != nullptr);
1846
1847 // configure waiting
1848 task->m_wait_obj->SetupWait(sync_obj, timeout);
1849
1850 // register ISyncObject if not yet
1851 if (sync_obj->GetHead() == nullptr)
1852 {
1853 m_sync_list->LinkBack(sync_obj);
1854 }
1855
1856 // start sleeping infinitely, we rely on a Wake call via WaitObject
1857 task->ScheduleSleep(WAIT_INFINITE);
1858
1859 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
1860 mutex->Unlock();
1861
1862 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1863 task->BusyWaitWhileSleeping();
1864
1865 // re-lock mutex when returning to the task's execution space
1866 mutex->Lock();
1867
1868 return (task->m_wait_obj->IsTimeout() ? WAIT_RESULT_TIMEOUT : WAIT_RESULT_SIGNAL);
1869 }
1870 else
1871 {
1872 STK_ASSERT(false);
1873 return WAIT_RESULT_FAIL;
1874 }
1875 }
1876
1877 TId OnGetTid(Word caller_SP) override
1878 {
1879 KernelTask *const task = FindTaskBySP(caller_SP);
1880 STK_ASSERT(task != nullptr);
1881
1882 return task->GetTid();
1883 }
1884
1885 void OnSuspend(bool suspended) override
1886 {
1887 // toggle kernel state
1888 if (suspended)
1889 {
1890 if (m_kstate == KSTATE_RUNNING)
1891 {
1893 }
1894 }
1895 else
1896 {
1897 if (m_kstate == KSTATE_SUSPENDED)
1898 {
1900 }
1901 }
1902
1903 // force yield for a currently active task
1904 if (!m_task_now->IsSleeping())
1905 {
1906 m_task_now->ScheduleSleep(YIELD_TICKS);
1907 }
1908 }
1909
1910 void OnInheritWeight(TId tid, Weight weight)
1911 {
1912 STK_ASSERT(tid != TID_NONE);
1913 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1914
1915 if (weight != NO_WEIGHT)
1916 {
1917 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1918 STK_ASSERT(task != nullptr);
1919
1920 const Weight prev_weight = task->GetWeight();
1921
1922 if (prev_weight < weight)
1923 {
1924 task->SetCurrentWeight(weight);
1925 m_strategy.OnTaskWeightChange(task, prev_weight);
1926 }
1927 }
1928 }
1929
1931 {
1932 STK_ASSERT(tid != TID_NONE);
1933 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
1934
1935 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
1936 STK_ASSERT(task != nullptr);
1937
1938 const Weight prev_weight = task->GetWeight();
1939
1940 // restore to original or boost from wait objects
1941 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
1942
1943 m_strategy.OnTaskWeightChange(task, prev_weight);
1944 }
1945
1948 Timeout UpdateTasks(const Timeout elapsed_ticks)
1949 {
1950 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
1952 {
1953 UpdateSyncObjects(elapsed_ticks);
1954 }
1955
1956 if (m_request != REQ_NONE)
1957 {
1959 }
1960
1961 return UpdateTaskState(elapsed_ticks);
1962 }
1963
1973 Timeout UpdateTaskState(const Timeout elapsed_ticks)
1974 {
1976
1977 for (size_t i = 0U; i < TASKS_MAX; ++i)
1978 {
1979 KernelTask *const task = &m_task_storage[i];
1980
1981 if (task->IsSleeping())
1982 {
1984 {
1985 // task is pending removal, wait until it is switched out
1986 if (task->IsPendingRemoval())
1987 {
1988 const size_t tasks_left = m_strategy.GetSize();
1989
1990 if ((task != m_task_now) ||
1991 ((tasks_left == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
1992 {
1993 RemoveTask(task);
1994 continue;
1995 }
1996 }
1997 }
1998
1999 // deliver sleep event to strategy
2000 // note: only currently scheduled task can be pending to sleep
2001 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2002 {
2003 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
2004 {
2005 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
2006
2007 // notify strategy that task is sleeping
2008 m_strategy.OnTaskSleep(task);
2009 }
2010 }
2011
2012 // advance sleep time by a tick
2013 task->m_time_sleep += elapsed_ticks;
2014
2015 // deliver sleep event to strategy
2016 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2017 {
2018 // notify strategy that task woke up
2019 if (!task->IsSleeping())
2020 {
2021 m_strategy.OnTaskWake(task);
2022 }
2023 }
2024 }
2025 else
2026 {
2028 {
2029 // in HRT mode we trace how long task spent in active state (doing some work)
2030 if (task->IsBusy())
2031 {
2032 task->m_hrt[0].duration += elapsed_ticks;
2033
2034 // check if deadline is missed (HRT failure)
2035 if (task->HrtIsDeadlineMissed(task->m_hrt[0].duration))
2036 {
2037 // report deadline overrun to a strategy which supports overrun recovery
2038 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
2039 {
2040 if (!m_strategy.OnTaskDeadlineMissed(task))
2041 {
2042 // report failure if it could not be recovered by the scheduling strategy
2043 task->HrtHardFailDeadline(&m_platform);
2044 }
2045 }
2046 else
2047 {
2048 task->HrtHardFailDeadline(&m_platform);
2049 }
2050 }
2051 }
2052 }
2053 }
2054
2055 // get the number ticks the driver has to keep CPU in Idle
2057 {
2058 if ((sleep_ticks > 1) && task->IsBusy())
2059 {
2060 sleep_ticks = task->GetSleepTicks(sleep_ticks);
2061 }
2062 }
2063 }
2064
2065 return sleep_ticks;
2066 }
2067
2070 void UpdateSyncObjects(const Timeout elapsed_ticks)
2071 {
2072 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
2073
2074 while (itr != nullptr)
2075 {
2076 ISyncObject::ListEntryType *const next = itr->GetNext();
2077
2078 if (!util::DListCast::ListEntryToParent<ISyncObject>(itr)->Tick(elapsed_ticks))
2079 {
2080 m_sync_list->Unlink(itr);
2081 }
2082
2083 itr = next;
2084 }
2085 }
2086
2090 {
2091 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2092 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2094 {
2095 // process serialized AddTask request made from another active task, requesting process
2096 // is currently waiting due to SwitchToNext()
2097 if ((m_request & REQ_ADD_TASK) != 0U)
2098 {
2100
2101 for (size_t i = 0U; i < TASKS_MAX; ++i)
2102 {
2103 KernelTask *const task = &m_task_storage[i];
2104
2105 if (task->m_srt[0].add_task_req != nullptr)
2106 {
2107 AllocateAndAddNewTask(task->m_srt[0].add_task_req->user_task);
2108
2109 task->m_srt[0].add_task_req = nullptr;
2110 __stk_full_memfence();
2111 }
2112 }
2113 }
2114 }
2115 }
2116
2121 EFsmEvent FetchNextEvent(KernelTask *&next)
2122 {
2124
2125 // try getting next task for scheduling
2127
2128 // sleep-aware strategy returns nullptr if no active tasks available
2129 if (next != nullptr)
2130 {
2131 // strategy must provide active-only task
2132 STK_ASSERT(!next->IsSleeping());
2133
2134 // if was sleeping, process wake event first
2136 }
2137 // start sleeping
2138 else
2139 {
2141 {
2142 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2143 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2144 if (m_strategy.GetSize() == 0U)
2145 {
2146 next = nullptr;
2147 type = FSM_EVENT_EXIT;
2148 }
2149 }
2150 }
2151
2152 return type;
2153 }
2154
2159#ifdef _STK_UNDER_TEST
2160 virtual
2161#endif
2162 EFsmState GetNewFsmState(KernelTask *&next)
2163 {
2165 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2166 }
2167
2173 bool UpdateFsmState(Stack *&idle, Stack *&active)
2174 {
2175 KernelTask *const now = m_task_now, *next = nullptr;
2176 bool switch_context = false;
2177
2178 const EFsmState new_state = GetNewFsmState(next);
2179
2180 switch (new_state)
2181 {
2183 switch_context = StateSwitch(now, next, idle, active);
2184 m_fsm_state = new_state;
2185 break;
2186 case FSM_STATE_SLEEPING:
2187 switch_context = StateSleep(now, next, idle, active);
2188 m_fsm_state = new_state;
2189 break;
2190 case FSM_STATE_WAKING:
2191 switch_context = StateWake(now, next, idle, active);
2192 m_fsm_state = new_state;
2193 break;
2194 case FSM_STATE_EXITING:
2195 switch_context = StateExit(now, next, idle, active);
2196 m_fsm_state = new_state;
2197 break;
2198 case FSM_STATE_NONE:
2199 break; // valid intermittent non-persisting state: no-transition
2200 case FSM_STATE_MAX:
2201 default: // invalid state value
2203 break;
2204 }
2205
2206 return switch_context;
2207 }
2208
2216 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2217 {
2218 STK_ASSERT(now != nullptr);
2219 STK_ASSERT(next != nullptr);
2220
2221 bool switch_context = false;
2222
2223 // if equal: do not switch context because task did not change
2224 if (next != now)
2225 {
2226 idle = now->GetUserStackPtr();
2227 active = next->GetUserStackPtr();
2228
2229 // if stack memory is exceeded these assertions will be hit
2230 if (now->IsBusy())
2231 {
2232 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2233 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2234 }
2235 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2236
2237 m_task_now = next;
2238
2240 {
2241 if (now->m_hrt[0].done)
2242 {
2243 now->HrtOnSwitchedOut();
2244 next->HrtOnSwitchedIn();
2245 }
2246 }
2247
2248 #if STK_SEGGER_SYSVIEW
2249 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SWITCH);
2250 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2251 #endif
2252
2253 switch_context = true;
2254 }
2255
2256 return switch_context;
2257 }
2258
2266 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2267 {
2268 STK_UNUSED(now);
2269
2270 STK_ASSERT(next != nullptr);
2271
2272 idle = &m_sleep_trap[0].stack;
2273 active = next->GetUserStackPtr();
2274
2275 // if stack memory is exceeded these assertions will be hit
2277 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2278
2279 m_task_now = next;
2280
2281 #if STK_SEGGER_SYSVIEW
2282 SEGGER_SYSVIEW_OnTaskStartReady(next->GetUserStackPtr()->tid);
2283 #endif
2284
2286 {
2287 next->HrtOnSwitchedIn();
2288 }
2289
2290 return true; // switch context
2291 }
2292
2300 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2301 {
2302 STK_UNUSED(next);
2303
2304 STK_ASSERT(now != nullptr);
2305 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
2306
2307 idle = now->GetUserStackPtr();
2308 active = &m_sleep_trap[0].stack;
2309
2311
2312 #if STK_SEGGER_SYSVIEW
2313 SEGGER_SYSVIEW_OnTaskStopReady(now->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2314 #endif
2315
2317 {
2318 if (!now->IsPendingRemoval())
2319 {
2320 now->HrtOnSwitchedOut();
2321 }
2322 }
2323
2324 return true; // switch context
2325 }
2326
2335 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2336 {
2337 STK_UNUSED(now);
2338 STK_UNUSED(next);
2339
2341 {
2342 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
2343 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
2344
2345 idle = nullptr;
2346 active = &m_exit_trap[0].stack;
2347
2348 m_task_now = nullptr;
2349
2350 m_platform.Stop();
2351 }
2352 else
2353 {
2354 STK_UNUSED(idle);
2355 STK_UNUSED(active);
2356 }
2357
2358 return false;
2359 }
2360
2364 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
2365
2371 {
2374 }
2375
2376#if STK_SEGGER_SYSVIEW
2381 void SendTaskTraceInfo(KernelTask *task)
2382 {
2383 STK_ASSERT(task->IsBusy());
2384
2385 SEGGER_SYSVIEW_TASKINFO info =
2386 {
2387 .TaskID = task->GetUserStackPtr()->tid,
2388 .sName = task->GetUserTask()->GetTraceName(),
2389 .Prio = 0,
2390 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
2391 .StackSize = task->GetUserTask()->GetStackSize() * sizeof(Word)
2392 };
2393 SEGGER_SYSVIEW_SendTaskInfo(&info);
2394 }
2395#endif
2396
2397 // Kernel modes:
2398 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
2399 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
2400 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
2401 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
2402 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
2403
2404 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
2406
2407 // If hit here: Kernel mode must be assigned.
2408 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
2409
2410 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
2411 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
2412 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
2413
2414 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
2415 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
2416 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
2417
2418 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
2419 // which destroys the precise periodicity HRT depends on.
2420 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
2421 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
2422
2423 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
2424 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
2425 !TStrategy::PRIORITY_INHERITANCE_API);
2426
2431
2446
2462
2469
2470 KernelService m_service;
2471 TPlatform m_platform;
2472 TStrategy m_strategy;
2473 KernelTask *m_task_now;
2475 SleepTrapStack m_sleep_trap[1];
2478 volatile uint8_t m_request;
2481
2483 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
2488 };
2489
2491};
2492
2493} // namespace stk
2494
2495#endif /* STK_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:654
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:484
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:218
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:455
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:298
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:428
#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:475
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
Definition stk_defs.h:502
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:202
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:140
@ 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:617
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:214
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:118
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:119
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:121
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:120
@ PERIODICITY_DEFAULT
Default periodicity (microseconds), 1 millisecond.
Definition stk_common.h:90
@ PERIODICITY_MAX
Maximum periodicity (microseconds), 99 milliseconds (note: this value is the highest working on a rea...
Definition stk_common.h:89
int64_t Ticks
Ticks value.
Definition stk_common.h:155
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:150
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:75
@ SYS_TASK_ID_EXIT
Exit trap.
Definition stk_common.h:100
@ SYS_TASK_ID_SLEEP
Sleep trap.
Definition stk_common.h:99
static constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:224
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:698
static constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:219
Timeout GetInitialSleepTicks()
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:208
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:202
static constexpr T Min(T a, T b) noexcept
Compile-time minimum of two values.
Definition stk_defs.h:692
@ TRACE_EVENT_SLEEP
Task entered sleep / blocked state.
Definition stk_common.h:111
@ TRACE_EVENT_SWITCH
Task context switch event (task became active).
Definition stk_common.h:110
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:80
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:79
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:81
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:608
Timeout GetInitialSleepTicks< true >()
Definition stk.h:39
uint64_t Cycles
Cycles value.
Definition stk_common.h:165
Word TId
Task (thread) id.
Definition stk_common.h:145
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:170
@ 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
@ 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
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).
Memory-related primitives.
void OnStop() override
Called by the platform driver after a scheduler stop (all tasks have exited).
Definition stk.h:1691
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2173
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1406
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1490
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:1818
void OnTaskSleepCancel(TId task_id)
Definition stk.h:1804
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1332
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:1535
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:2430
~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:1718
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:1835
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:1885
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1143
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2162
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel when it is not started.
Definition stk.h:1118
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:1930
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:1621
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:2266
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:1556
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1372
static constexpr bool IsHrtMode()
Definition stk.h:2400
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:1054
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:2468
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1346
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:1228
static constexpr bool IsSyncMode()
Definition stk.h:2401
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance.
Definition stk.h:1514
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1364
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:1910
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1208
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:1750
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1280
static constexpr bool IsTicklessMode()
Definition stk.h:2402
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:1596
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1446
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1324
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:2335
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1315
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1461
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:1745
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:1017
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:1476
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:1877
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1252
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:1948
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:2370
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:2364
static constexpr bool IsDynamicMode()
Definition stk.h:2399
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1320
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2216
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:1093
Kernel()
Construct the kernel with all storage zero-initialized, m_request cleared to REQ_NONE,...
Definition stk.h:984
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2089
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:2300
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, advance sleep timers, and track HRT durations.
Definition stk.h:1973
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:2070
static constexpr bool IsStaticMode()
Definition stk.h:2398
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1307
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:1774
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1171
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2121
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:257
KernelTask()
Construct a free (unbound) task slot. All fields set to zero/null.
Definition stk.h:157
void ScheduleSleep(Timeout ticks)
Put the task into a sleeping state for the specified number of ticks.
Definition stk.h:737
Timeout GetSleepTicks(Timeout sleep_ticks)
Definition stk.h:344
TId GetTid() const
Get task identifier.
Definition stk.h:190
void HrtOnSwitchedOut()
Called when task is switched out from the scheduling process.
Definition stk.h:680
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_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:277
friend class Kernel
Definition stk.h:127
bool HrtIsDeadlineMissed(Timeout duration) const
Check if deadline missed.
Definition stk.h:723
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:773
void ScheduleRemoval()
Schedule the removal of the task from the kernel on next tick.
Definition stk.h:595
Stack m_stack
Stack descriptor (SP register value + access mode + optional tid).
Definition stk.h:770
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:544
~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:775
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:700
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:655
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:771
void BusyWaitWhileSleeping() const
Block further execution of the task's context while in sleeping state.
Definition stk.h:756
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:769
Timeout GetHrtRelativeDeadline() const override
Get remaining HRT deadline (ticks left before the deadline expires).
Definition stk.h:325
void SetCurrentWeight(Weight weight) override
Update the run-time scheduling weight (weighted strategies only).
Definition stk.h:207
Stack GetUserStack() const override
Get stack descriptor for this task slot.
Definition stk.h:175
bool IsBusy() const
Check whether this slot is bound to a user task.
Definition stk.h:180
bool IsSleeping() const override
Check whether this task is currently sleeping (waiting for a tick or a wake event).
Definition stk.h:185
Stack * GetUserStackPtr()
Get pointer to user Stack.
Definition stk.h:767
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:774
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:714
void Wake() override
Wake this task on the next scheduling tick.
Definition stk.h:196
Weight GetWeight() const override
Get static scheduling weight from the user task.
Definition stk.h:218
volatile Timeout m_time_sleep
Sleep countdown: negative while sleeping (absolute value = ticks remaining), zero when awake.
Definition stk.h:772
bool IsPendingRemoval() const
Check if task is pending removal.
Definition stk.h:612
Timeout GetHrtDeadline() const override
Get absolute HRT deadline (ticks elapsed since task was activated).
Definition stk.h:300
void Unbind()
Reset this slot to the free (unbound) state, clearing all scheduling metadata.
Definition stk.h:570
void HrtOnSwitchedIn()
Called when task is switched into the scheduling process.
Definition stk.h:675
bool IsMemoryOfSP(Word SP) const
Check if Stack Pointer (SP) belongs to this task.
Definition stk.h:617
ITask * GetUserTask() override
Get bound user task.
Definition stk.h:170
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:776
Payload for an in-flight AddTask() request issued by a running task.
Definition stk.h:149
ITask * user_task
User task to add. Must remain valid for the lifetime of its kernel slot.
Definition stk.h:150
Per-task soft real-time (SRT) metadata.
Definition stk.h:389
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:395
AddTaskRequest * add_task_req
Definition stk.h:405
Per-task Hard Real-Time (HRT) scheduling metadata.
Definition stk.h:413
void Clear()
Clear all fields, ready for slot re-use or re-activation.
Definition stk.h:419
volatile bool done
Set to true when the task signals work completion (via Yield() or on exit). Triggers HrtOnSwitchedOut...
Definition stk.h:430
Timeout deadline
Maximum allowed active duration in ticks (relative to switch-in). Exceeding this triggers OnDeadlineM...
Definition stk.h:428
Timeout periodicity
Activation period in ticks: the task is re-activated every this many ticks.
Definition stk.h:427
Timeout duration
Ticks spent in the active (non-sleeping) state in the current period. Incremented by UpdateTaskState(...
Definition stk.h:429
Concrete implementation of IWaitObject, embedded in each KernelTask slot.
Definition stk.h:440
bool IsWaiting() const
Check if busy with waiting.
Definition stk.h:472
Timeout m_time_wait
Ticks remaining until timeout. Decremented each tick; WAIT_INFINITE means no timeout.
Definition stk.h:537
void Wake(bool timeout) override
Wake the waiting task (called by ISyncObject when it signals).
Definition stk.h:479
~WaitObject()=default
Destructor.
bool Tick(Timeout elapsed_ticks) override
Advance the timeout countdown by one tick.
Definition stk.h:498
bool IsTimeout() const override
Check whether the wait expired due to timeout.
Definition stk.h:467
void SetupWait(ISyncObject *sync_obj, Timeout timeout)
Configure and arm this wait object for a new wait operation.
Definition stk.h:523
TId GetTid() const override
Get the TId of the task that owns this wait object.
Definition stk.h:462
volatile bool m_timeout
true if the wait expired due to timeout rather than a Wake() signal.
Definition stk.h:536
ISyncObject * m_sync_obj
Sync object this wait is registered with, or NULL when not waiting.
Definition stk.h:535
KernelTask * m_task
Back-pointer to the owning KernelTask. Set once at construction; never changes.
Definition stk.h:534
Payload stored in the sync object's kernel-side list entry while a task is waiting.
Definition stk.h:455
ISyncObject * sync_obj
Sync object whose Tick() will be called each kernel tick.
Definition stk.h:456
KernelService()
Construct an uninitialized service instance (m_platform = null, m_ticks = 0).
Definition stk.h:940
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:895
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:856
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:968
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:799
friend class Kernel
Definition stk.h:788
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:816
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:967
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:793
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:848
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:908
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:832
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:928
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:920
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:797
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:795
void Wake(ISyncObject *sobj, bool all)
Wake one or all tasks currently waiting on a synchronization object.
Definition stk.h:876
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:801
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:791
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:863
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:961
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:953
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2440
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:2441
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:2444
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2443
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:2456
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:2460
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:2457
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:2459
RAII instance that enters the critical section on construction and exits it on destruction.
Definition stk_arch.h:386
Lightweight, non-owning view over a contiguous sequence of elements.
Definition stk_common.h:251
size_t GetSize() const
Get number of elements in the view.
Definition stk_common.h:291
Stack descriptor.
Definition stk_common.h:380
uint32_t access_mode
Bitfield with hardware access mode of the task (see EAccessMode).
Definition stk_common.h:382
TId tid
Task id (see STK_SEGGER_SYSVIEW, STK_MPU_STACK_GUARD).
Definition stk_common.h:393
Interface for a stack memory region.
Definition stk_common.h:401
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:444
Synchronization object interface.
Definition stk_common.h:544
virtual void WakeAll()=0
Wake all tasks currently in the wait list.
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:557
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:552
static void AddWaitObject(IWaitObject::ListHeadType &wlist, IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:563
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:334
Interface for mutex synchronization primitive.
Definition stk_common.h:677
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:734
virtual EAccessMode GetAccessMode() const =0
Get hardware access mode of the user task.
virtual void OnExit()
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
Definition stk_common.h:827
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:854
Interface for a platform driver.
Definition stk_common.h:946
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
Definition stk_common.h:954
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:614
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.