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"
20
36
37namespace stk {
38
39// Helper function for Kernel::UpdateTaskState.
40template <bool TicklessMode> __stk_forceinline Timeout GetInitialSleepTicks();
43
94template <uint8_t TMode, uint32_t TSize, class TStrategy, class TPlatform>
95class Kernel
96#ifndef _STK_UNDER_TEST
97final
98#endif
99: public IKernel, private IPlatform::IEventHandler
100{
101protected:
107
113
118 enum ERequest : uint8_t
119 {
121 REQ_ADD_TASK = (1 << 0)
122 };
123
135 class KernelTask final : public IKernelTask
136 {
137 friend class Kernel;
138
143 enum EStateFlags : uint32_t
144 {
148 STATE_WAKE_PENDING = (1U << 2),
149 STATE_SUSPENDED = (1U << 3),
151 };
152
153 public:
162 {
164 };
165
172 {
173 // bind to wait object
175 {
176 m_wait_obj[0].m_task = this;
177 }
178 }
179
183 ITask *GetUserTask() override { return m_user; }
184
188 const ITask *GetUserTask() const { return m_user; }
189
193 Stack GetUserStack() const override { return m_stack;}
194
198 bool IsBusy() const { return (m_user != nullptr); }
199
203 __stk_forceinline bool IsSleeping() const override { return (m_time_sleep < 0); }
204
209
213 TId GetTid() const { return GetTidFromUserTask(m_user); }
214
219 void Wake() override
220 {
222
223 // wakeup on a next cycle
224 m_time_sleep = -1;
225
226 // notify kernel that this task, even if was going to sleep will be woken on a next tick
227 if ((m_state & STATE_SLEEP_PENDING) != 0U)
228 {
230 }
231 }
232
236 void SetCurrentWeight(Weight weight) override
237 {
238 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
239 {
240 m_rt_weight[0] = weight;
241 }
242 }
243
247 Weight GetWeight() const override
248 {
249 Weight static_weight;
250
251 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
252 {
253 if (m_rt_weight[0] != NO_WEIGHT)
254 {
255 static_weight = m_rt_weight[0];
256 }
257 else
258 {
259 static_weight = GetBaseWeight();
260 }
261 }
262 else
263 {
264 static_weight = GetBaseWeight();
265 }
266
267 return static_weight;
268 }
269
273 Weight GetBaseWeight() const override
274 {
275 Weight base_weight;
276
277 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
278 {
279 // run-time override set via IKernelService::SetWeight() takes precedence
280 base_weight = (m_base_weight[0] != NO_WEIGHT ? m_base_weight[0] : m_user->GetWeight());
281 }
282 else
283 {
284 base_weight = DEFAULT_WEIGHT;
285 }
286
287 return base_weight;
288 }
289
294 {
295 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
296 {
297 m_base_weight[0] = weight;
298 }
299 else
300 {
301 STK_UNUSED(weight);
302 }
303 }
304
310 Weight GetCurrentWeight() const override
311 {
312 Weight cur_weight;
313
314 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
315 {
316 cur_weight = m_rt_weight[0];
317 }
318 else
319 {
320 cur_weight = DEFAULT_WEIGHT;
321 }
322
323 return cur_weight;
324 }
325
330 Timeout GetHrtPeriodicity() const override
331 {
333
334 Timeout to;
335
337 {
338 to = m_hrt[0].periodicity;
339 }
340 else
341 {
342 to = 0;
343 }
344
345 return to;
346 }
347
353 Timeout GetHrtDeadline() const override
354 {
356
357 Timeout deadline;
358
360 {
361 deadline = m_hrt[0].deadline;
362 }
363 else
364 {
365 deadline = 0;
366 }
367
368 return deadline;
369 }
370
379 {
382
383 Timeout relative_deadline;
384
386 {
387 const typename KernelTask::HrtInfo &hrt = m_hrt[0];
388
389 relative_deadline = (hrt.deadline - hrt.duration);
390 }
391 else
392 {
393 relative_deadline = 0;
394 }
395
396 return relative_deadline;
397 }
398
400 {
401 // note: task sleep time is negative
403
405 {
406 typename KernelTask::WaitObject &wait_obj = m_wait_obj[0];
407
408 // likely task is sleeping during sync operation (see Wait)
409 if (wait_obj.IsWaiting())
410 {
411 // note: sync wait time is positive
412 task_sleep = wait_obj.m_time_wait;
413
414 // we shall account for only valid time (when task is waiting during sync operation)
415 if (task_sleep > NO_WAIT)
416 {
417 sleep_ticks = Min(sleep_ticks, task_sleep);
418 }
419 }
420 else
421 {
422 sleep_ticks = Min(sleep_ticks, task_sleep);
423 }
424 }
425 else
426 {
427 sleep_ticks = Min(sleep_ticks, task_sleep);
428 }
429
430 // clamp to [1, STK_TICKLESS_TICKS_MAX] range
431 return Max<Timeout>(1, sleep_ticks);
432 }
433
434 protected:
439
445 struct SrtInfo
446 {
448 {}
449
452 void Clear()
453 {
454 add_task_req = nullptr;
455 }
456
463 };
464
469 struct HrtInfo
470 {
471 HrtInfo() : periodicity(0), deadline(0), duration(0), done(false)
472 {}
473
476 void Clear()
477 {
478 periodicity = 0;
479 deadline = 0;
480 duration = 0;
481 done = false;
482 }
483
487 volatile bool done;
488 };
489
494 struct TsInfo
495 {
498
501 void Clear()
502 {
505 }
506
509 void Reload()
510 {
511 left = quantum;
512 }
513
515 volatile Timeout left;
516 };
517
524 struct WaitObject final : public IWaitObject
525 {
526 explicit WaitObject() : m_task(nullptr), m_sync_obj(nullptr), m_time_wait(NO_WAIT),
528 {}
529
534
541 {
543 };
544
548 TId GetTid() const override { return m_task->GetTid(); }
549
554 EState GetState() const override { return m_state; }
555
559 bool IsWaiting() const { return (m_sync_obj != nullptr); }
560
566 {
568
569 switch (GetState())
570 {
571 case STATE_TIMEOUT:
572 return WAIT_RESULT_TIMEOUT;
573 case STATE_CANCELLED:
575 default: {
579 return WAIT_RESULT_SIGNAL; }
580 }
581 }
582
587 {
589
591 }
592
598 void Wake(bool timeout) override
599 {
601
602 m_state = (timeout ? STATE_TIMEOUT : STATE_SIGNALED);
604
605 m_sync_obj->RemoveWaitObject(this);
606 m_sync_obj = nullptr;
607
608 return m_task->Wake();
609 }
610
617 bool Tick(Timeout elapsed_ticks) override
618 {
620 {
621 if (m_state == STATE_WAIT)
622 {
623 m_time_wait -= elapsed_ticks;
624
625 if (m_time_wait <= NO_WAIT)
626 {
628 }
629 }
630 }
631
632 return (m_state == STATE_WAIT);
633 }
634
642 void SetupWait(ISyncObject *sync_obj, Timeout timeout)
643 {
645
646 m_sync_obj = sync_obj;
647 m_time_wait = timeout;
649
650 sync_obj->AddWaitObject(this);
651 }
652
661 {
662 if (IsWaiting())
663 {
665
666 m_sync_obj->RemoveWaitObject(this);
667 m_sync_obj = nullptr;
668 }
669 }
670
682 void Cancel()
683 {
685
688
689 m_sync_obj->RemoveWaitObject(this);
690 m_sync_obj = nullptr;
691
692 m_task->Wake();
693 }
694
700 {
701 const bool was_waiting = IsWaiting();
702 if (was_waiting)
703 {
704 Cancel();
705 }
706
707 return was_waiting;
708 }
709
713 volatile EState m_state;
714 };
715
720 void Bind(TPlatform *platform, ITask *user_task)
721 {
722 // bind user task (GetTid depends on m_user)
723 m_user = user_task;
724
725 // set access mode for this stack
726 m_stack.access_mode = user_task->GetAccessMode();
727
728 // set task id for tracking purpose
729 #if STK_STACK_NEEDS_TASK_ID
730 m_stack.tid = GetTid();
732 #endif
733
734 // init stack of the user task
735 platform->InitStack(STACK_USER_TASK, &m_stack, user_task, user_task);
736
737 // initialize current weight to NO_WEIGHT for priority inheritance mechanism
738 if __stk_constexpr_cpp17 (TStrategy::PRIORITY_INHERITANCE_API)
739 {
741 }
742
743 // no run-time override of the base weight: ITask::GetWeight() is used
744 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API)
745 {
747 }
748
749 // time-slice quantum of the task, the first slice starts full
751 {
752 const Timeout quantum = user_task->GetTimeSlice();
753 STK_ASSERT(quantum >= NO_TIME_SLICE);
754
755 typename KernelTask::TsInfo &ts = m_ts[0];
756
757 ts.quantum = quantum;
758 ts.left = quantum;
759 }
760 }
761
765 void Unbind()
766 {
768 {
769 // should be freed from waiting on task exit
770 STK_ASSERT(!m_wait_obj[0].IsWaiting());
771 }
772
773 m_user = nullptr;
774 m_stack = {};
776 m_time_sleep = 0;
777
779 {
780 m_hrt[0].Clear();
781 }
782 else
783 {
784 m_srt[0].Clear();
785 }
786
788 {
789 m_ts[0].Clear();
790 }
791 }
792
805 void ScheduleRemoval(Kernel *const kernel)
806 {
807 // if blocked on a sync object, detach first - otherwise the WaitObject stays linked
808 // in the sync object's wait list after Unbind() frees this slot, and a later
809 // Wake()/WakeAll() would corrupt whatever task the slot gets rebound to
811 {
812 m_wait_obj[0].CancelNoWake();
813 }
814
815 // make this task sleeping to switch it out from scheduling process
817
818 // mark it as done HRT task
820 {
822 }
823
824 // mark it as pending for removal
826
827 // the task may not be the current one (e.g. removed via ScheduleTaskRemoval() by another task):
828 // deliver the sleep entry now, otherwise a forced context switch could pick this task from the
829 // strategy although it IsSleeping(); skipped if the task was already sleeping (flag is not set
830 // then, the strategy has already been notified)
831 if ((this != kernel->m_task_now) && ((m_state & STATE_SLEEP_PENDING) != 0U))
832 {
833 kernel->ProcessTaskPendingSleep(this);
834 }
835 }
836
839 bool IsPendingRemoval() const { return ((m_state & STATE_REMOVE_PENDING) != 0U); }
840
844 bool IsMemoryOfSP(Word SP) const
845 {
846 bool is_match = false;
847
848 const Word start = hw::PtrToWord(m_user->GetStack());
849 const Word end = start + (m_user->GetStackSize() * sizeof(Word));
850
851 if ((SP >= start) && (SP <= end))
852 {
853 is_match = true;
854 }
855 #if STK_TZ_SECURE // lookup Secure memory region too when on a Secure side
856 else
857 {
858 IStackMemory *const secure_mem = m_user->GetSecureStackMemory();
859
860 if (secure_mem != nullptr)
861 {
862 const Word s_start = hw::PtrToWord(secure_mem->GetStack());
863 const Word s_end = s_start + (secure_mem->GetStackSize() * sizeof(Word));
864
865 if ((SP >= s_start) && (SP <= s_end))
866 {
867 is_match = true;
868 }
869 }
870 }
871 #endif
872
873 return is_match;
874 }
875
882 void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
883 {
884 STK_ASSERT(periodicity_tc > 0);
885 STK_ASSERT(deadline_tc > 0);
886 STK_ASSERT(start_delay_tc >= 0);
887 STK_ASSERT(periodicity_tc < INT32_MAX);
888 STK_ASSERT(deadline_tc < INT32_MAX);
889
890 typename KernelTask::HrtInfo &hrt = m_hrt[0];
891
892 hrt.periodicity = periodicity_tc;
893 hrt.deadline = deadline_tc;
894
895 if (start_delay_tc > 0)
896 {
897 ScheduleSleep(start_delay_tc);
898 }
899 }
900
905
910 {
911 typename KernelTask::HrtInfo &hrt = m_hrt[0];
912
913 const Timeout duration = hrt.duration;
914
915 STK_ASSERT(duration >= 0);
916
917 const Timeout sleep = hrt.periodicity - duration;
918 if (sleep > 0)
919 {
920 ScheduleSleep(sleep);
921 }
922
923 hrt.duration = 0;
924 hrt.done = false;
925 }
926
932 {
933 const Timeout duration = m_hrt[0].duration;
934
935 STK_ASSERT(duration >= 0);
937
938 m_user->OnDeadlineMissed(duration);
939 platform->ProcessHardFault();
940 }
941
946 {
947 m_hrt[0].done = true;
948 __stk_full_memfence();
949 }
950
954 bool HrtIsDeadlineMissed(Timeout duration) const
955 {
956 return (duration > m_hrt[0].deadline);
957 }
958
969 {
970 STK_ASSERT(ticks > 0);
971
972 // set state first as kernel checks it when task IsSleeping
973 if (!IsSleeping())
974 {
976 }
977
978 m_time_sleep = -ticks;
979
980 // task leaves the CPU voluntarily: its next run starts with a full slice
982 {
983 m_ts[0].Reload();
984 }
985
986 __stk_full_memfence();
987 }
988
992 {
993 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API)
994 {
996
997 // yielding restarts the slice (tx_thread_relinquish semantics)
999 {
1000 m_ts[0].Reload();
1001 }
1002
1003 __stk_full_memfence();
1004 }
1005 }
1006
1009 void BusyWaitWhileYielding(Kernel *const kernel) const
1010 {
1011 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API)
1012 {
1013 kernel->m_platform.ForceContextSwitch(GetTid());
1014
1015 while ((m_state & STATE_YIELD_PENDING) != 0U)
1016 {
1017 __stk_relax_cpu();
1018 }
1019 }
1020 }
1021
1024 void BusyWaitWhileSleeping(Kernel *kernel) const
1025 {
1026 kernel->m_platform.ForceContextSwitch(GetTid());
1027
1028 while (IsSleeping())
1029 {
1030 __stk_relax_cpu();
1031 }
1032 }
1033
1038
1041 volatile uint32_t m_state;
1049 };
1050
1058 class KernelService final : public IKernelService
1059 {
1060 friend class Kernel;
1061
1062 public:
1063 TId GetTid() const override { return m_kernel->m_platform.GetTid(); }
1064
1065 Ticks GetTicks() const override { return hw::ReadVolatile64(&m_ticks); }
1066
1067 uint32_t GetTickResolution() const override { return m_kernel->m_platform.GetTickResolution(); }
1068
1069 Cycles GetSysTimerCount() const override { return m_kernel->m_platform.GetSysTimerCount(); }
1070
1071 uint32_t GetSysTimerFrequency() const override { return m_kernel->m_platform.GetSysTimerFrequency(); }
1072
1073 void Delay(Timeout ticks) override
1074 {
1076 STK_ASSERT(ticks >= 0);
1077
1078 Ticks now = GetTicks();
1079 const Ticks deadline = now + ticks;
1080 STK_ASSERT(deadline >= now);
1081
1082 for (; now < deadline; now = GetTicks())
1083 {
1084 __stk_relax_cpu();
1085 }
1086 }
1087
1088 void Sleep(Timeout ticks) override
1089 {
1091 STK_ASSERT(ticks >= 0);
1092
1094 {
1095 m_kernel->m_platform.Sleep(ticks);
1096 }
1097 else
1098 {
1099 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
1100 STK_ASSERT(false);
1101 }
1102 }
1103
1104 bool SleepUntil(Ticks timestamp) override
1105 {
1107
1109 {
1110 return m_kernel->m_platform.SleepUntil(timestamp);
1111 }
1112 else
1113 {
1114 // sleeping is not supported in HRT mode, task will sleep according to its periodicity and workload
1115 STK_ASSERT(false);
1116 return false;
1117 }
1118 }
1119
1120 void SleepCancel(TId task_id) override
1121 {
1123 {
1124 m_kernel->CancelTaskWait(GetUserTaskFromTid(task_id));
1125 }
1126 }
1127
1128 void SwitchToNext() override
1129 {
1131
1132 m_kernel->m_platform.SwitchToNext();
1133 }
1134
1135 EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout ticks) override
1136 {
1138 {
1139 return m_kernel->m_platform.Wait(sobj, mutex, ticks);
1140 }
1141 else
1142 {
1143 STK_ASSERT(false);
1144 return WAIT_RESULT_FAIL;
1145 }
1146 }
1147
1148 void Wake(ISyncObject *sobj, bool all) override
1149 {
1151 {
1152 if (all)
1153 {
1155 }
1156 else
1157 {
1159 }
1160 }
1161 else
1162 {
1163 STK_ASSERT(false);
1164 }
1165 }
1166
1167 Timeout Suspend() override
1168 {
1170 {
1171 return m_kernel->m_platform.Suspend();
1172 }
1173 else
1174 {
1175 STK_ASSERT(false);
1176 return 0;
1177 }
1178 }
1179
1180 void Resume(Timeout elapsed_ticks) override
1181 {
1183 {
1184 return m_kernel->m_platform.Resume(elapsed_ticks);
1185 }
1186 else
1187 {
1188 STK_ASSERT(false);
1189 }
1190 }
1191
1192 void InheritWeight(TId tid, Weight weight) override
1193 {
1194 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API)
1195 {
1196 m_kernel->OnInheritWeight(tid, weight);
1197 }
1198 }
1199
1200 void RestoreWeight(TId tid, ISyncObject *sobj) override
1201 {
1202 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API)
1203 {
1204 m_kernel->OnRestoreWeight(tid, sobj);
1205 }
1206 }
1207
1208 Weight SetWeight(TId tid, Weight weight) override
1209 {
1210 Weight result;
1211
1212 if __stk_constexpr_cpp17 (TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API)
1213 {
1214 // critical section: avoid race with OnTick
1215
1217
1218 result = m_kernel->OnSetWeight(tid, weight);
1219 }
1220 else
1221 {
1222 // strategy must handle OnTaskWeightChange() events
1223 STK_UNUSED(tid);
1224 STK_UNUSED(weight);
1225 STK_ASSERT(false);
1226
1227 result = NO_WEIGHT;
1228 }
1229
1230 return result;
1231 }
1232
1233 Timeout SetTimeSlice(TId tid, Timeout ticks) override
1234 {
1235 Timeout result;
1236
1238 {
1239 // critical section: avoid race with OnTick
1240
1242
1243 result = m_kernel->OnSetTimeSlice(tid, ticks);
1244 }
1245 else
1246 {
1247 STK_UNUSED(tid);
1248 STK_UNUSED(ticks);
1249 STK_ASSERT(false);
1250
1251 result = NO_TIME_SLICE;
1252 }
1253
1254 return result;
1255 }
1256
1257 private:
1261 explicit KernelService() : m_kernel(nullptr), m_ticks(0)
1262 {}
1263
1268
1274 void Initialize(Kernel *kernel)
1275 {
1276 m_kernel = kernel;
1277 }
1278
1282 void IncrementTicks(Ticks advance)
1283 {
1284 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
1285 hw::WriteVolatile64(&m_ticks, m_ticks + advance);
1286 }
1287
1289 volatile Ticks m_ticks;
1290 };
1291
1292public:
1295 static constexpr size_t TASKS_MAX = TSize;
1296
1307 {
1308 #ifdef _DEBUG
1309 // TPlatform must inherit IPlatform
1310 IPlatform *platform = &m_platform;
1311 STK_UNUSED(platform);
1312
1313 // TStrategy must inherit ITaskSwitchStrategy
1314 ITaskSwitchStrategy *strategy = &m_strategy;
1315 STK_UNUSED(strategy);
1316 #endif
1317
1318 #if !STK_TICKLESS_IDLE
1319 STK_STATIC_ASSERT_DESC(((TMode & KERNEL_TICKLESS) == 0U),
1320 "STK_TICKLESS_IDLE must be defined to 1 for KERNEL_TICKLESS");
1321 #endif
1322 }
1323
1328
1338 __stk_attr_noinline void Initialize(uint32_t resolution_us = PERIODICITY_DEFAULT) override
1339 {
1340 STK_ASSERT(resolution_us != 0);
1341 STK_ASSERT(resolution_us <= PERIODICITY_MAX);
1343
1344 // reinitialize key state variables
1345 m_task_now = nullptr;
1348
1349 // exit trap is required only for KERNEL_DYNAMIC mode
1350 Stack *exit_trap;
1352 {
1353 exit_trap = &m_exit_trap[0].stack;
1354 }
1355 else
1356 {
1357 exit_trap = nullptr;
1358 }
1359
1360 m_service.Initialize(this);
1361 m_platform.Initialize(this, &m_service, resolution_us, exit_trap);
1362
1363 // now ready to Start()
1365 }
1366
1375 __stk_attr_noinline void AddTask(ITask *user_task) override
1376 {
1378 {
1379 STK_ASSERT(user_task != nullptr);
1381
1382 // when started the operation must be serialized by switching out from processing until
1383 // kernel processes this request
1384 if (IsStarted())
1385 {
1387 {
1388 RequestAddTask(user_task);
1389 }
1390 else
1391 {
1392 STK_ASSERT(false);
1393 }
1394 }
1395 else
1396 {
1397 AllocateAndAddNewTask(user_task);
1398 }
1399 }
1400 else
1401 {
1402 STK_ASSERT(false);
1403 }
1404 }
1405
1414 __stk_attr_noinline void AddTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc,
1415 Timeout start_delay_tc) override
1416 {
1418 {
1419 STK_ASSERT(user_task != nullptr);
1422
1423 HrtAllocateAndAddNewTask(user_task, periodicity_tc, deadline_tc, start_delay_tc);
1424 }
1425 else
1426 {
1427 STK_ASSERT(false);
1428 }
1429 }
1430
1439 __stk_attr_noinline void RemoveTask(ITask *user_task) override
1440 {
1442 {
1443 STK_ASSERT(user_task != nullptr);
1445
1446 KernelTask *const task = FindTaskByUserTask(user_task);
1447 if (task != nullptr)
1448 {
1449 RemoveTask(task);
1450 }
1451 }
1452 else
1453 {
1454 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1455 STK_ASSERT(false);
1456 }
1457 }
1458
1465 {
1467 {
1468 STK_ASSERT(user_task != nullptr);
1470
1471 // critical section: avoid race with OnTick
1472
1474
1475 KernelTask *const task = FindTaskByUserTask(user_task);
1476 if (task != nullptr)
1477 {
1478 task->ScheduleRemoval(this);
1479 }
1480 }
1481 else
1482 {
1483 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to be removed
1484 STK_ASSERT(false);
1485 }
1486 }
1487
1494 void SuspendTask(ITask *user_task, bool &suspended) override
1495 {
1496 STK_ASSERT(user_task != nullptr);
1497
1498 bool self = false;
1499 KernelTask *self_task = nullptr;
1500
1501 // critical section: avoid race with OnTick
1502 {
1504
1505 KernelTask *const task = FindTaskByUserTask(user_task);
1506 STK_ASSERT(task != nullptr);
1507
1508 // nesting not supported, must not be suspended by SuspendTask
1509 STK_ASSERT((task->m_state & KernelTask::STATE_SUSPENDED) == 0U);
1510
1511 // only suspend if the task is currently awake: if it is already sleeping
1512 // (e.g. blocked on a mutex or timed Sleep), do not overwrite m_time_sleep,
1513 // that would corrupt the original sleep state and, for sync-object waits,
1514 // would interfere with WaitObject::Tick()
1515 suspended = !task->IsSleeping();
1516 if (suspended == true)
1517 {
1518 task->ScheduleSleep(WAIT_INFINITE);
1519
1520 // check if suspending self
1521 self = (task == m_task_now);
1522
1523 // trace blocked via Suspend
1524 if (self)
1525 {
1526 // keep the pointer: m_task_now may change as soon as the critical section is released
1527 self_task = task;
1528
1529 #if STK_SEGGER_SYSVIEW
1530 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SUSPEND);
1531 #endif
1532 }
1533
1534 // set state
1535 task->m_state |= KernelTask::STATE_SUSPENDED;
1536 }
1537 }
1538
1539 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
1540 if (self_task != nullptr)
1541 {
1542 self_task->BusyWaitWhileSleeping(this);
1543 }
1544 }
1545
1551 void ResumeTask(ITask *user_task) override
1552 {
1553 STK_ASSERT(user_task != nullptr);
1554
1555 // critical section: avoid race with OnTick
1556
1558
1559 KernelTask *const task = FindTaskByUserTask(user_task);
1560 STK_ASSERT(task != nullptr);
1561
1562 // must be suspended by SuspendTask, otherwise noop
1563 if ((task->m_state & KernelTask::STATE_SUSPENDED) != 0U)
1564 {
1565 // clear state
1566 task->m_state &= ~KernelTask::STATE_SUSPENDED;
1567
1568 // wake up
1569 if (task->IsSleeping())
1570 {
1571 task->Wake();
1572 }
1573 }
1574 }
1575
1579 void CancelTaskWait(ITask *user_task) override
1580 {
1581 STK_ASSERT(user_task != nullptr);
1582
1583 KernelTask *const task = FindTaskByUserTask(user_task);
1584 if (task != nullptr)
1585 {
1586 // critical section: avoid race with OnTick
1587
1589
1590 bool canceled_wait = false;
1591
1593 {
1594 // a task blocked in OnTaskWait() also counts as sleeping (ScheduleSleep(WAIT_INFINITE)), but
1595 // its WaitObject is still linked into the sync object's wait list: waking only the task
1596 // would leave a stale entry behind (later signaled or ticked as a timeout while the task is
1597 // not waiting), so cancel the wait itself, this unlinks it, records WAIT_RESULT_CANCELED
1598 // and wakes the task
1599 canceled_wait = task->m_wait_obj[0].CancelIfWaiting();
1600 }
1601
1602 if (!canceled_wait && task->IsSleeping())
1603 {
1604 task->Wake();
1605 }
1606 }
1607 }
1608
1618 bool GetTaskState(ITask *user_task, TaskStateInfo &info) const override
1619 {
1620 bool result;
1621
1622 if (IsTelemetryMode())
1623 {
1624 if (user_task != nullptr)
1625 {
1627 info.wait_obj = nullptr;
1628 info.remaining = WAIT_INFINITE;
1629
1630 // critical section: consistent view against OnTick
1632
1633 const KernelTask *const task = FindTaskByUserTask(user_task);
1634 if (task != nullptr)
1635 {
1636 bool resolved = false;
1637
1638 if ((task->m_state & KernelTask::STATE_REMOVE_PENDING) != 0U)
1639 {
1641 resolved = true;
1642 }
1643 else if ((task->m_state & KernelTask::STATE_SUSPENDED) != 0U)
1644 {
1646 resolved = true;
1647 }
1648 else
1649 {
1651 {
1652 const typename KernelTask::WaitObject &wait_obj = task->m_wait_obj[0];
1653
1654 if (wait_obj.IsWaiting())
1655 {
1657 info.wait_obj = wait_obj.m_sync_obj;
1658 info.remaining = wait_obj.m_time_wait;
1659 resolved = true;
1660 }
1661 }
1662 }
1663
1664 if (!resolved)
1665 {
1666 const Timeout time_sleep = task->m_time_sleep;
1667
1668 if (time_sleep < 0)
1669 {
1671 info.remaining = -time_sleep; // -(-WAIT_INFINITE) == WAIT_INFINITE for an infinite sleep
1672 }
1673 else
1674 {
1675 info.state = TASK_STATE_READY;
1676 }
1677 }
1678 }
1679
1680 result = true;
1681 }
1682 else
1683 {
1684 result = false;
1685 }
1686 }
1687 else
1688 {
1689 result = false;
1690 }
1691
1692 return result;
1693 }
1694
1700 {
1701 size_t count = 0U;
1702 const size_t limit = Min(tasks.GetSize(), TASKS_MAX);
1703
1704 // critical section: avoid race with OnTick
1705 {
1707
1708 for (size_t i = 0U; i < limit; ++i)
1709 {
1710 KernelTask &task = m_task_storage[i];
1711 if (task.IsBusy())
1712 {
1713 tasks[count++] = &task;
1714 }
1715 }
1716 }
1717
1718 return count;
1719 }
1720
1725 size_t EnumerateTasks(ArrayView<ITask *> user_tasks) override
1726 {
1727 size_t count = 0U;
1728 const size_t limit = Min(user_tasks.GetSize(), TASKS_MAX);
1729
1730 // critical section: avoid race with OnTick
1731 {
1733
1734 for (size_t i = 0U; i < limit; ++i)
1735 {
1736 KernelTask &task = m_task_storage[i];
1737 if (task.IsBusy())
1738 {
1739 user_tasks[count++] = task.GetUserTask();
1740 }
1741 }
1742 }
1743
1744 return count;
1745 }
1746
1756 {
1758
1759 // stacks of the traps must be re-initilized on every subsequent Start
1760 InitTraps();
1761
1762 // start tracing
1763 #if STK_SEGGER_SYSVIEW
1764 SEGGER_SYSVIEW_Start();
1765 for (size_t i = 0U; i < TASKS_MAX; ++i)
1766 {
1767 KernelTask *task = &m_task_storage[i];
1768 if (task->IsBusy())
1769 {
1770 SendTaskTraceInfo(task);
1771 }
1772 }
1773 #endif
1774
1775 m_platform.Start();
1776 }
1777
1782 bool IsStarted() const
1783 {
1784 return (m_task_now != nullptr);
1785 }
1786
1790 IPlatform *GetPlatform() override { return &m_platform; }
1791
1796
1799 EKernelState GetState() const override { return m_kstate; }
1800
1801 // Used by tests only, not Public API:
1802#ifdef _STK_UNDER_TEST
1803 void ScheduleSleepOnActiveTask(Timeout ticks)
1804 {
1805 m_task_now->ScheduleSleep(ticks);
1806 }
1807#endif
1808
1809protected:
1823
1836
1843 static constexpr Timeout YIELD_TICKS = 1;
1844
1848 {
1849 return ((state > FSM_STATE_NONE) && (state < FSM_STATE_MAX));
1850 }
1851
1855 {
1856 // init stack for a Sleep trap
1857 {
1858 SleepTrapStack &sleep = m_sleep_trap[0];
1859
1860 SleepTrapStackMemory wrapper(&sleep.memory);
1861 sleep.stack.access_mode = ACCESS_PRIVILEGED;
1862 #if STK_STACK_NEEDS_TASK_ID
1863 sleep.stack.tid = SYS_TASK_ID_SLEEP;
1864 #endif
1865
1866 STK_UNUSED(m_platform.InitStack(STACK_SLEEP_TRAP, &sleep.stack, &wrapper, nullptr));
1867 }
1868
1869 // init stack for an Exit trap
1871 {
1872 ExitTrapStack &exit = m_exit_trap[0];
1873
1874 ExitTrapStackMemory wrapper(&exit.memory);
1875 exit.stack.access_mode = ACCESS_PRIVILEGED;
1876 #if STK_STACK_NEEDS_TASK_ID
1877 exit.stack.tid = SYS_TASK_ID_EXIT;
1878 #endif
1879
1880 STK_UNUSED(m_platform.InitStack(STACK_EXIT_TRAP, &exit.stack, &wrapper, nullptr));
1881 }
1882 }
1883
1888 KernelTask *AllocateNewTask(ITask *user_task)
1889 {
1890 // look for a free kernel task
1891 KernelTask *new_task = nullptr;
1892 for (size_t i = 0U; i < TASKS_MAX; ++i)
1893 {
1894 KernelTask *const task = &m_task_storage[i];
1895 if (task->IsBusy())
1896 {
1897 // avoid task collision
1898 STK_ASSERT(task->m_user != user_task);
1899
1900 // avoid stack collision
1901 STK_ASSERT(task->m_user->GetStack() != user_task->GetStack());
1902 }
1903 else
1904 if (new_task == nullptr)
1905 {
1906 new_task = task;
1907 #if defined(NDEBUG) && !defined(_STK_ASSERT_REDIRECT)
1908 break; // break if assertions are inactive and do not try to validate collision with existing tasks
1909 #endif
1910 }
1911 else
1912 {
1913 // noop, continue to the next slot
1914 }
1915 }
1916
1917 // if nullptr - exceeded max supported kernel task count, application design failure
1918 STK_ASSERT(new_task != nullptr);
1919
1920 new_task->Bind(&m_platform, user_task);
1921
1922 return new_task;
1923 }
1924
1928 void AddKernelTask(KernelTask *task)
1929 {
1930 #if STK_SEGGER_SYSVIEW
1931 // start tracing new task
1932 SEGGER_SYSVIEW_OnTaskCreate(task->GetUserStackPtr()->tid);
1933 if (IsStarted())
1934 {
1935 SendTaskTraceInfo(task);
1936 }
1937 #endif
1938
1939 m_strategy.AddTask(task);
1940 }
1941
1946 {
1947 KernelTask *const task = AllocateNewTask(user_task);
1948 STK_ASSERT(task != nullptr);
1949
1950 AddKernelTask(task);
1951 }
1952
1960 void HrtAllocateAndAddNewTask(ITask *user_task, Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
1961 {
1962 KernelTask *const task = AllocateNewTask(user_task);
1963 STK_ASSERT(task != nullptr);
1964
1965 task->HrtInit(periodicity_tc, deadline_tc, start_delay_tc);
1966
1967 AddKernelTask(task);
1968 }
1969
1975 {
1976 KernelTask *const caller = FindTaskBySP(m_platform.GetCallerSP());
1977 STK_ASSERT(caller != nullptr);
1978
1979 typename KernelTask::SrtInfo &srt = caller->m_srt[0];
1980
1981 typename KernelTask::AddTaskRequest req = { .user_task = user_task };
1982 srt.add_task_req = &req;
1983
1984 // notify kernel
1986
1987 // switch out and wait for completion (due to context switch request could be processed here)
1988 if (srt.add_task_req != nullptr)
1989 {
1990 m_service.SwitchToNext();
1991 }
1992
1993 // wait until request is consumed
1994 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API)
1995 {
1996 while (srt.add_task_req != nullptr)
1997 {
1998 __stk_relax_cpu();
1999 }
2000 }
2001
2002 STK_ASSERT(srt.add_task_req == nullptr);
2003 }
2004
2005 template <typename TaskPtr, typename Storage>
2006 static inline TaskPtr FindTaskByUserTaskImpl(const ITask *user_task, Storage &task_storage)
2007 {
2008 TaskPtr found_task = nullptr;
2009
2010 for (size_t i = 0U; i < TASKS_MAX; ++i)
2011 {
2012 TaskPtr const task = &task_storage[i];
2013
2014 if (task->GetUserTask() == user_task)
2015 {
2016 found_task = task;
2017 break;
2018 }
2019 }
2020
2021 return found_task;
2022 }
2023
2028 __stk_attr_noinline KernelTask *FindTaskByUserTask(const ITask *user_task)
2029 {
2031 }
2032
2037 __stk_attr_noinline const KernelTask *FindTaskByUserTask(const ITask *user_task) const
2038 {
2040 }
2041
2046 KernelTask *FindTaskByStack(const Stack *stack)
2047 {
2048 KernelTask *found_task = nullptr;
2049
2050 for (size_t i = 0U; i < TASKS_MAX; ++i)
2051 {
2052 KernelTask *const task = &m_task_storage[i];
2053 if (task->GetUserStackPtr() == stack)
2054 {
2055 found_task = task;
2056 break;
2057 }
2058 }
2059
2060 return found_task;
2061 }
2062
2068 {
2069 STK_ASSERT(m_task_now != nullptr);
2070
2071 KernelTask *found_task = nullptr;
2072
2073 if (m_task_now->IsMemoryOfSP(SP))
2074 {
2075 found_task = m_task_now;
2076 }
2077 else
2078 {
2079 for (size_t i = 0U; i < TASKS_MAX; ++i)
2080 {
2081 KernelTask *const task = &m_task_storage[i];
2082
2083 // skip finished tasks (applicable only for KERNEL_DYNAMIC mode)
2085 {
2086 if (!task->IsBusy())
2087 {
2088 continue;
2089 }
2090 }
2091
2092 if (task->IsMemoryOfSP(SP))
2093 {
2094 found_task = task;
2095 break;
2096 }
2097 }
2098 }
2099
2100 return found_task;
2101 }
2102
2107 void RemoveTask(KernelTask *task)
2108 {
2109 STK_ASSERT(task != nullptr);
2110
2111 #if STK_SEGGER_SYSVIEW
2112 SEGGER_SYSVIEW_OnTaskTerminate(task->GetUserStackPtr()->tid);
2113 #endif
2114
2115 // notify task about pending exit
2116 task->GetUserTask()->OnExit();
2117
2118 m_strategy.RemoveTask(task);
2119 task->Unbind();
2120 }
2121
2132 __stk_attr_noinline void OnStart(Stack *&active) override
2133 {
2134 STK_ASSERT(m_strategy.GetSize() != 0);
2135
2136 // iterate tasks and generate OnTaskSleep for a strategy for all initially sleeping tasks
2137 for (size_t i = 0U; i < TASKS_MAX; ++i)
2138 {
2139 KernelTask *const task = &m_task_storage[i];
2140
2141 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
2142 {
2143 STK_ASSERT(task->IsSleeping());
2144
2145 task->m_state &= ~KernelTask::STATE_SLEEP_PENDING;
2146
2147 // notify strategy that task is sleeping
2148 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2149 {
2150 m_strategy.OnTaskSleep(task);
2151 }
2152 }
2153 }
2154
2155 // get initial state and first task
2156 {
2158
2159 KernelTask *next = nullptr;
2161
2162 // expecting only SLEEPING or SWITCHING states
2164
2166 {
2167 m_task_now = next;
2168 active = next->GetUserStackPtr();
2169
2171 {
2172 next->HrtOnSwitchedIn();
2173 }
2174 }
2175 else
2177 {
2179 active = &m_sleep_trap[0].stack;
2180 }
2181 else
2182 {
2183 // unexpected state
2185 }
2186 }
2187
2188 // is in running state
2190 }
2191
2198 {
2200 {
2202
2203 // is in stopped state, i.e. is ready to Start() again
2205 }
2206 }
2207
2224 bool OnTick(Stack *&idle, Stack *&active
2225 #if STK_TICKLESS_IDLE
2226 , Timeout &ticks
2227 #endif
2228 ) override
2229 {
2230 #if !STK_TICKLESS_IDLE
2231 // in non-tickless mode kernel is advancing strictly by 1 tick on every OnTick call
2232 enum { ticks = 1 };
2233 #endif
2234
2235 // elapsed ticks must be captured here: in tickless mode "ticks" is overwritten below
2236 const Timeout elapsed_ticks = ticks;
2237
2238 // advance internal timestamp
2239 m_service.IncrementTicks(elapsed_ticks);
2240
2241 // consume elapsed and update to ticks to sleep
2242 #if STK_TICKLESS_IDLE
2243 ticks = (
2244 #else
2245 // notify compiler that we ignore a return value of UpdateTasks
2246 STK_UNUSED(
2247 #endif
2248 UpdateTasks(elapsed_ticks));
2249
2250 // time-slice accounting for the task that just ran (after sleep/wake updates, before the FSM picks next)
2252 {
2253 UpdateTimeslice(elapsed_ticks);
2254 }
2255
2256 // decide on a context switch
2257 return UpdateFsmState(idle, active);
2258 }
2259
2260 bool OnForceContextSwitch(TId id, Stack *&idle, Stack *&active)
2261 {
2262 bool switch_context = false;
2263 KernelTask *const task = m_task_now;
2264
2265 STK_ASSERT(task != nullptr);
2266
2267 // note: called from inside ISR, therefore protection by critical section is not needed
2268
2269 if (task->GetTid() == id)
2270 {
2271 // current task is busy-waiting to be de-scheduled
2272 if (task->IsSleeping())
2273 {
2274 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
2275 {
2277
2278 switch_context = UpdateFsmState(idle, active);
2279 }
2280 }
2281 else
2282 {
2283 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API)
2284 {
2285 // current task yielded and stays runnable: let the strategy pick the next task
2286 if ((task->m_state & KernelTask::STATE_YIELD_PENDING) != 0U)
2287 {
2289
2290 switch_context = UpdateFsmState(idle, active);
2291 }
2292 }
2293 }
2294 }
2295
2296 return switch_context;
2297 }
2298
2299 void OnTaskSwitch(Word caller_SP) override
2300 {
2301 // let the strategy handle the yield without putting the task to sleep (e.g. to hand
2302 // the CPU to same-priority peers only), not applicable in HRT mode where Yield()
2303 // means work completion
2304 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API && !IsHrtMode())
2305 {
2306 KernelTask *const task = FindTaskBySP(caller_SP);
2307 STK_ASSERT(task != nullptr);
2308
2309 if (task != nullptr)
2310 {
2311 bool handled = false;
2312
2313 // critical section: avoid race with OnTick
2314 {
2316
2317 if (!task->IsSleeping())
2318 {
2319 if (m_strategy.OnTaskYield(task))
2320 {
2321 task->ScheduleYield();
2322 handled = true;
2323 }
2324 }
2325 }
2326
2327 if (handled)
2328 {
2329 task->BusyWaitWhileYielding(this);
2330 }
2331 else
2332 {
2333 OnTaskSleep(caller_SP, YIELD_TICKS);
2334 }
2335 }
2336 else
2337 {
2338 // defensive: do nothing on null task
2339 }
2340 }
2341 else
2342 {
2343 OnTaskSleep(caller_SP, YIELD_TICKS);
2344 }
2345 }
2346
2347 void OnTaskSleep(Word caller_SP, Timeout ticks) override
2348 {
2349 KernelTask *const task = FindTaskBySP(caller_SP);
2350 STK_ASSERT(task != nullptr);
2351
2352 // // critical section: make change to HRT state and sleep time atomic
2353 {
2355
2357 {
2358 task->HrtOnWorkCompleted();
2359 }
2360
2361 if (ticks > 0)
2362 {
2363 task->ScheduleSleep(ticks);
2364
2365 // trace blocked on Sleep
2366 #if STK_SEGGER_SYSVIEW
2367 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2368 #endif
2369 }
2370 }
2371
2372 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
2373 task->BusyWaitWhileSleeping(this);
2374 }
2375
2376 bool OnTaskSleepUntil(Word caller_SP, Ticks timestamp) override
2377 {
2378 KernelTask *const task = FindTaskBySP(caller_SP);
2379 STK_ASSERT(task != nullptr);
2380
2381 bool result = true;
2382
2383 // critical section: make change to HRT state and sleep time atomic
2384 {
2386
2387 // calculate signed delta (handles wrap-around correctly)
2388 const Ticks delta = timestamp - m_service.m_ticks;
2389
2390 if (delta > 0)
2391 {
2392 const Ticks infinite_ticks = WAIT_INFINITE;
2393 task->ScheduleSleep(static_cast<Timeout>(Min(delta, infinite_ticks)));
2394
2395 // trace blocked on on SleepUntil
2396 #if STK_SEGGER_SYSVIEW
2397 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_SLEEP);
2398 #endif
2399 }
2400 else
2401 {
2402 result = false; // deadline already hit or passed
2403 }
2404 }
2405
2406 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
2407 if (result)
2408 {
2409 task->BusyWaitWhileSleeping(this);
2410 }
2411
2412 return result;
2413 }
2414
2415 void OnTaskExit(Stack *stack) override
2416 {
2418 {
2419 KernelTask *const task = FindTaskByStack(stack);
2420 STK_ASSERT(task != nullptr);
2421
2422 // task is being stopped and will terminate
2423 #if STK_SEGGER_SYSVIEW
2424 SEGGER_SYSVIEW_OnTaskStopExec();
2425 #endif
2426
2427 // critical section: avoid race with OnTick
2428 {
2429 // make change to HRT/sleep/removal state atomic (same as OnTaskSleep/OnTaskSleepUntil)
2431
2432 // notify kernel to execute removal (asynchronous operation)
2433 task->ScheduleRemoval(this);
2434 }
2435 }
2436 else
2437 {
2438 // kernel operating mode must be KERNEL_DYNAMIC for tasks to be able to exit
2440 }
2441 }
2442
2443 EWaitResult OnTaskWait(Word caller_SP, ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
2444 {
2446 {
2447 STK_ASSERT(timeout != 0); // API contract: caller must not be in ISR
2448 STK_ASSERT(sync_obj != nullptr); // API contract: ISyncObject instance must be provided
2449 STK_ASSERT(mutex != nullptr); // API contract: IMutex instance must be provided
2450 STK_ASSERT((sync_obj->GetHead() == nullptr) || (sync_obj->GetHead() == &m_sync_list[0]));
2451
2452 KernelTask *const task = FindTaskBySP(caller_SP);
2453 STK_ASSERT(task != nullptr);
2454
2455 typename KernelTask::WaitObject &wait_obj = task->m_wait_obj[0];
2456
2457 // critical section: avoid race with OnTick
2458 {
2459 // keep the task from being de-scheduled between ScheduleSleep() and the end of mutex->Unlock():
2460 // otherwise a tick can switch it out (sleeping) while it still owns the mutex
2462
2463 // configure waiting
2464 wait_obj.SetupWait(sync_obj, timeout);
2465
2466 // register ISyncObject if not yet
2467 if (sync_obj->GetHead() == nullptr)
2468 {
2469 m_sync_list->LinkBack(sync_obj);
2470 }
2471
2472 // start sleeping infinitely, we rely on a Wake call via WaitObject
2473 task->ScheduleSleep(WAIT_INFINITE);
2474
2475 // trace blocked on sync object's Wait
2476 #if STK_SEGGER_SYSVIEW
2477 SEGGER_SYSVIEW_OnTaskStopReady(task->GetUserStackPtr()->tid, TRACE_EVENT_WAIT);
2478 #endif
2479
2480 // unlock mutex locked externally, so that we could wait in a busy-waiting loop
2481 mutex->Unlock();
2482 }
2483
2484 // note: we do not spin long here, kernel will switch this task out from scheduling on the next tick
2485 task->BusyWaitWhileSleeping(this);
2486
2487 // extract & clear this wait's result BEFORE mutex->Lock(): a contended Lock() recurses
2488 // into OnTaskWait() and reuses this same per-task WaitObject, which would otherwise
2489 // silently overwrite/clear our still-unread result
2490 const EWaitResult result = wait_obj.GetWaitResult();
2491 wait_obj.ClearState();
2492
2493 // re-lock mutex when returning to the task's execution space
2494 mutex->Lock();
2495
2496 return result;
2497 }
2498 else
2499 {
2500 STK_ASSERT(false);
2501 return WAIT_RESULT_FAIL;
2502 }
2503 }
2504
2505 TId OnGetTid(Word caller_SP) override
2506 {
2507 KernelTask *const task = FindTaskBySP(caller_SP);
2508 STK_ASSERT(task != nullptr);
2509
2510 return task->GetTid();
2511 }
2512
2513 void OnSuspend(bool suspended) override
2514 {
2515 // toggle kernel state
2516 if (suspended)
2517 {
2518 if (m_kstate == KSTATE_RUNNING)
2519 {
2521 }
2522 }
2523 else
2524 {
2525 if (m_kstate == KSTATE_SUSPENDED)
2526 {
2528 }
2529 }
2530
2531 // force yield for a currently active task
2532 if (!m_task_now->IsSleeping())
2533 {
2534 m_task_now->ScheduleSleep(YIELD_TICKS);
2535 }
2536 }
2537
2538 void OnInheritWeight(TId tid, Weight weight)
2539 {
2540 STK_ASSERT(tid != TID_NONE);
2541 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
2542
2543 if (weight != NO_WEIGHT)
2544 {
2545 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
2546 STK_ASSERT(task != nullptr);
2547
2548 const Weight prev_weight = task->GetWeight();
2549
2550 if (prev_weight < weight)
2551 {
2552 task->SetCurrentWeight(weight);
2553 m_strategy.OnTaskWeightChange(task, prev_weight);
2554 }
2555 }
2556 }
2557
2559 {
2560 STK_ASSERT(tid != TID_NONE);
2561 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
2562 STK_ASSERT(weight != NO_WEIGHT);
2563
2564 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
2565 STK_ASSERT(task != nullptr);
2566
2567 const Weight prev_weight = task->GetWeight(); // effective weight (base or inherited)
2568 const Weight prev_base = task->GetBaseWeight();
2569
2570 task->SetBaseWeight(weight);
2571
2572 // an inherited weight that does not exceed the new base weight is no longer a boost
2573 if ((task->GetCurrentWeight() != NO_WEIGHT) && (task->GetCurrentWeight() <= weight))
2574 {
2575 task->SetCurrentWeight(NO_WEIGHT);
2576 }
2577
2578 // always notify: the strategy may depend on parts of the weight that do not change
2579 // the effective weight while a boost is active (e.g. preemption-threshold)
2580 m_strategy.OnTaskWeightChange(task, prev_weight);
2581
2582 return prev_base;
2583 }
2584
2586 {
2587 STK_ASSERT(tid != TID_NONE);
2588 STK_ASSERT(ticks >= NO_TIME_SLICE);
2589
2590 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
2591 STK_ASSERT(task != nullptr);
2592
2593 typename KernelTask::TsInfo &ts = task->m_ts[0];
2594
2595 const Timeout prev = ts.quantum;
2596
2597 ts.quantum = ticks;
2598 ts.Reload();
2599
2600 return prev;
2601 }
2602
2607 void UpdateTimeslice(const Timeout elapsed_ticks)
2608 {
2609 KernelTask *const task = m_task_now;
2610
2611 // only a real, runnable task is charged: not the sleep trap, not a task which is leaving
2612 if ((task != nullptr) &&
2614 task->IsBusy() && !task->IsSleeping())
2615 {
2616 typename KernelTask::TsInfo &ts = task->m_ts[0];
2617
2618 if (ts.quantum != NO_TIME_SLICE)
2619 {
2620 ts.left -= elapsed_ticks;
2621
2622 if (ts.left <= 0)
2623 {
2624 ts.Reload();
2625
2626 // strategy rotates to a same-priority peer if there is one, otherwise (or if the
2627 // task is not eligible) the task keeps running with a fresh slice
2628 STK_UNUSED(m_strategy.OnTaskTimeSlice(task));
2629 }
2630 }
2631 }
2632 }
2633
2635 {
2636 STK_ASSERT(tid != TID_NONE);
2637 STK_ASSERT(TStrategy::WEIGHT_API && TStrategy::PRIORITY_INHERITANCE_API);
2638
2639 KernelTask *const task = FindTaskByUserTask(GetUserTaskFromTid(tid));
2640 STK_ASSERT(task != nullptr);
2641
2642 const Weight prev_weight = task->GetWeight();
2643
2644 // restore to original or boost from wait objects
2645 task->SetCurrentWeight(sobj != nullptr ? sobj->FindWeightHigherThan(task->GetWeight()) : NO_WEIGHT);
2646
2647 m_strategy.OnTaskWeightChange(task, prev_weight);
2648 }
2649
2652 Timeout UpdateTasks(const Timeout elapsed_ticks)
2653 {
2654 // sync objects are updated before UpdateTaskRequest which may add a new object (newly added object must become 1 tick older)
2656 {
2657 UpdateSyncObjects(elapsed_ticks);
2658 }
2659
2660 if (m_request != REQ_NONE)
2661 {
2663 }
2664
2665 return UpdateTaskState(elapsed_ticks);
2666 }
2667
2668 void ProcessTaskPendingSleep(KernelTask *const task)
2669 {
2671
2672 // notify strategy that task is sleeping
2673 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2674 {
2675 m_strategy.OnTaskSleep(task);
2676 }
2677 }
2678
2679 void ProcessTaskPendingYield(KernelTask *const task)
2680 {
2681 task->m_state &= ~KernelTask::STATE_YIELD_PENDING;
2682 }
2683
2684
2715 Timeout UpdateTaskState(const Timeout elapsed_ticks)
2716 {
2718
2719 for (size_t i = 0U; i < TASKS_MAX; ++i)
2720 {
2721 KernelTask *const task = &m_task_storage[i];
2722
2723 if __stk_constexpr_cpp17 (TStrategy::NOSLEEP_YIELD_API)
2724 {
2725 // a pending yield is consumed by this tick (the strategy already moved its cursor)
2726 if ((task->m_state & KernelTask::STATE_YIELD_PENDING) != 0U)
2727 {
2728 task->m_state &= ~KernelTask::STATE_YIELD_PENDING;
2729 }
2730 }
2731
2732 if (task->IsSleeping())
2733 {
2735 {
2736 // task is pending removal, wait until it is switched out
2737 if (task->IsPendingRemoval())
2738 {
2739 const size_t tasks_left = m_strategy.GetSize();
2740
2741 if ((task != m_task_now) ||
2742 ((tasks_left == 1U) && (m_fsm_state == FSM_STATE_SLEEPING)))
2743 {
2744 RemoveTask(task);
2745 continue;
2746 }
2747 }
2748 }
2749
2750 bool just_entered_sleep = false;
2751
2752 // note: only currently scheduled task can be pending to sleep
2753 if ((task->m_state & KernelTask::STATE_SLEEP_PENDING) != 0U)
2754 {
2755 STK_ASSERT(elapsed_ticks == 1); // entry tick must be a single, uncoalesced tick
2756
2757 // if Wake() raced in before this entry tick ran, STATE_WAKE_PENDING is set:
2758 // deliver OnTaskSleep() below as usual, then fall through to the advance block
2759 // in this same pass instead of waiting an extra tick, so the paired OnTaskWake()
2760 // still fires on schedule.
2761 const bool wake_pending = ((task->m_state & KernelTask::STATE_WAKE_PENDING) != 0U);
2762
2764
2765 just_entered_sleep = !wake_pending;
2766 }
2767
2768 if (!just_entered_sleep && !task->IsSleepInfinite())
2769 {
2770 // advance sleep time by number of elapsed ticks (always 1 if non-Tickless)
2771 task->m_time_sleep += elapsed_ticks;
2772
2773 // deliver sleep event to the strategy
2774 if __stk_constexpr_cpp17 (TStrategy::SLEEP_EVENT_API)
2775 {
2776 // notify strategy that the task woke up
2777 if (!task->IsSleeping())
2778 {
2779 m_strategy.OnTaskWake(task);
2780 }
2781 }
2782 }
2783 }
2784 else
2785 {
2787 {
2788 // in HRT mode we trace how long task spent in active state (doing some work)
2789 if (task->IsBusy())
2790 {
2791 typename KernelTask::HrtInfo &hrt = task->m_hrt[0];
2792
2793 hrt.duration += elapsed_ticks;
2794
2795 // check if deadline is missed (HRT failure)
2796 if (task->HrtIsDeadlineMissed(hrt.duration))
2797 {
2798 // report deadline overrun to the strategy which supports overrun recovery
2799 if __stk_constexpr_cpp17 (TStrategy::DEADLINE_MISSED_API)
2800 {
2801 if (!m_strategy.OnTaskDeadlineMissed(task))
2802 {
2803 // report failure if it could not be recovered by the scheduling strategy
2804 task->HrtHardFailDeadline(&m_platform);
2805 }
2806 }
2807 else
2808 {
2809 task->HrtHardFailDeadline(&m_platform);
2810 }
2811 }
2812 }
2813 }
2814 }
2815
2816 // get the number of ticks the driver has to keep CPU in Idle
2818 {
2819 if ((sleep_ticks > 1) && task->IsBusy())
2820 {
2821 sleep_ticks = task->GetSleepTicks(sleep_ticks);
2822 }
2823 }
2824 }
2825
2826 return sleep_ticks;
2827 }
2828
2831 void UpdateSyncObjects(const Timeout elapsed_ticks)
2832 {
2833 ISyncObject::ListEntryType *itr = m_sync_list->GetFirst();
2834
2835 while (itr != nullptr)
2836 {
2837 ISyncObject::ListEntryType *const next = itr->GetNext();
2838
2839 if (!util::DListCast::ListEntryToParent<ISyncObject>(itr)->Tick(elapsed_ticks))
2840 {
2841 m_sync_list->Unlink(itr);
2842 }
2843
2844 itr = next;
2845 }
2846 }
2847
2851 {
2852 // process AddTask requests coming from tasks (KERNEL_DYNAMIC mode only, KERNEL_HRT is
2853 // excluded as we assume that HRT tasks must be known to the kernel before a Start())
2855 {
2856 // process serialized AddTask request made from another active task, requesting process
2857 // is currently waiting due to SwitchToNext()
2858 if ((m_request & REQ_ADD_TASK) != 0U)
2859 {
2861
2862 for (size_t i = 0U; i < TASKS_MAX; ++i)
2863 {
2864 KernelTask *const task = &m_task_storage[i];
2865
2866 typename KernelTask::SrtInfo &srt = task->m_srt[0];
2867
2868 if (srt.add_task_req != nullptr)
2869 {
2870 AllocateAndAddNewTask(srt.add_task_req->user_task);
2871
2872 srt.add_task_req = nullptr;
2873 __stk_full_memfence();
2874 }
2875 }
2876 }
2877 }
2878 }
2879
2884 EFsmEvent FetchNextEvent(KernelTask *&next)
2885 {
2887
2888 // try getting next task for scheduling
2890
2891 // sleep-aware strategy returns nullptr if no active tasks available
2892 if (next != nullptr)
2893 {
2894 // strategy must provide active-only task
2895 STK_ASSERT(!next->IsSleeping());
2896
2897 // if was sleeping, process wake event first
2899 }
2900 // start sleeping
2901 else
2902 {
2904 {
2905 // if nullptr is returned then either strategy has all tasks sleeping or none left,
2906 // if KERNEL_DYNAMIC mode and no tasks left then exit from scheduling
2907 if (m_strategy.GetSize() == 0U)
2908 {
2909 next = nullptr;
2910 type = FSM_EVENT_EXIT;
2911 }
2912 }
2913 }
2914
2915 return type;
2916 }
2917
2922#ifdef _STK_UNDER_TEST
2923 virtual
2924#endif
2925 EFsmState GetNewFsmState(KernelTask *&next)
2926 {
2928 return m_fsm[m_fsm_state][FetchNextEvent(next)];
2929 }
2930
2936 bool UpdateFsmState(Stack *&idle, Stack *&active)
2937 {
2938 KernelTask *const now = m_task_now, *next = nullptr;
2939 bool switch_context = false;
2940
2941 const EFsmState new_state = GetNewFsmState(next);
2942
2943 switch (new_state)
2944 {
2946 switch_context = StateSwitch(now, next, idle, active);
2947 m_fsm_state = new_state;
2948 break;
2949 case FSM_STATE_SLEEPING:
2950 switch_context = StateSleep(now, next, idle, active);
2951 m_fsm_state = new_state;
2952 break;
2953 case FSM_STATE_WAKING:
2954 switch_context = StateWake(now, next, idle, active);
2955 m_fsm_state = new_state;
2956 break;
2957 case FSM_STATE_EXITING:
2958 switch_context = StateExit(now, next, idle, active);
2959 m_fsm_state = new_state;
2960 break;
2961 case FSM_STATE_NONE:
2962 break; // valid intermittent non-persisting state: no-transition
2963 case FSM_STATE_MAX:
2964 default: // invalid state value
2966 break;
2967 }
2968
2969 return switch_context;
2970 }
2971
2979 bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
2980 {
2981 STK_ASSERT(now != nullptr);
2982 STK_ASSERT(next != nullptr);
2983
2984 bool switch_context = false;
2985
2986 // if equal: do not switch context because task did not change
2987 if (next != now)
2988 {
2989 idle = now->GetUserStackPtr();
2990 active = next->GetUserStackPtr();
2991
2992 // if stack memory is exceeded these assertions will be hit
2993 #if STK_STACK_GUARD
2994 if (now->IsBusy())
2995 {
2996 // current task could exit, thus we check it with IsBusy to avoid referencing nullptr returned by GetUserTask()
2997 STK_ASSERT(now->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
2998 }
2999 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
3000 #endif
3001
3002 m_task_now = next;
3003
3005 {
3006 if (now->m_hrt[0].done)
3007 {
3008 now->HrtOnSwitchedOut();
3009 next->HrtOnSwitchedIn();
3010 }
3011 }
3012
3013 switch_context = true;
3014 }
3015
3016 return switch_context;
3017 }
3018
3026 bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
3027 {
3028 STK_UNUSED(now);
3029
3030 STK_ASSERT(next != nullptr);
3031
3032 idle = &m_sleep_trap[0].stack;
3033 active = next->GetUserStackPtr();
3034
3035 // if stack memory is exceeded these assertions will be hit
3037 #if STK_STACK_GUARD
3038 STK_ASSERT(next->GetUserTask()->GetStack()[0] == STK_STACK_MEMORY_FILLER);
3039 #endif
3040
3041 m_task_now = next;
3042
3044 {
3045 next->HrtOnSwitchedIn();
3046 }
3047
3048 return true; // switch context
3049 }
3050
3058 bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
3059 {
3060 STK_UNUSED(next);
3061
3062 STK_ASSERT(now != nullptr);
3063 STK_ASSERT(m_sleep_trap[0].stack.SP != 0);
3064
3065 idle = now->GetUserStackPtr();
3066 active = &m_sleep_trap[0].stack;
3067
3069
3071 {
3072 if (!now->IsPendingRemoval())
3073 {
3074 now->HrtOnSwitchedOut();
3075 }
3076 }
3077
3078 return true; // switch context
3079 }
3080
3089 bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
3090 {
3091 STK_UNUSED(now);
3092 STK_UNUSED(next);
3093
3095 {
3096 // dynamic tasks are not supported if main processes's stack memory is not provided in Start()
3097 STK_ASSERT(m_exit_trap[0].stack.SP != 0);
3098
3099 idle = nullptr;
3100 active = &m_exit_trap[0].stack;
3101
3102 m_task_now = nullptr;
3103
3104 m_platform.Stop();
3105 }
3106 else
3107 {
3108 STK_UNUSED(idle);
3109 STK_UNUSED(active);
3110 }
3111
3112 return false;
3113 }
3114
3118 bool IsInitialized() const { return (m_kstate != KSTATE_INACTIVE); }
3119
3125 {
3126 // critical section: avoid race with OnTick
3127 {
3129
3131 }
3132 }
3133
3134#if STK_SEGGER_SYSVIEW
3139 void SendTaskTraceInfo(KernelTask *task)
3140 {
3141 STK_ASSERT(task->IsBusy());
3142
3143 const SEGGER_SYSVIEW_TASKINFO info =
3144 {
3145 .TaskID = task->GetUserStackPtr()->tid,
3146 .sName = task->GetUserTask()->GetTraceName(),
3147 .Prio = static_cast<U32>(task->GetWeight()),
3148 .StackBase = hw::PtrToWord(task->GetUserTask()->GetStack()),
3149 .StackSize = (task->GetUserTask()->GetStackSize() * sizeof(Word))
3150 };
3151 SEGGER_SYSVIEW_SendTaskInfo(&info);
3152 }
3153#endif
3154
3155 // Kernel modes:
3156 static constexpr bool IsStaticMode() { return ((TMode & KERNEL_STATIC) != 0U); }
3157 static constexpr bool IsDynamicMode() { return ((TMode & KERNEL_DYNAMIC) != 0U); }
3158 static constexpr bool IsHrtMode() { return ((TMode & KERNEL_HRT) != 0U); }
3159 static constexpr bool IsSyncMode() { return ((TMode & KERNEL_SYNC) != 0U); }
3160 static constexpr bool IsTicklessMode() { return ((TMode & KERNEL_TICKLESS) != 0U); }
3161 static constexpr bool IsTimesliceMode() { return ((TMode & KERNEL_TIMESLICE) != 0U); }
3162 static constexpr bool IsTelemetryMode() { return ((TMode & KERNEL_TELEMETRY) != 0U); }
3163
3164 // If hit here: Kernel<N> expects at least 1 task, e.g. N > 0
3166
3167 // If hit here: Kernel mode must be assigned.
3168 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TMode != 0U));
3169
3170 // If hit here: KERNEL_STATIC and KERNEL_DYNAMIC can not be mixed, either one of these is possible.
3171 STK_STATIC_ASSERT_N(KERNEL_MODE_MIX_NOT_ALLOWED,
3172 (((TMode & KERNEL_STATIC) & (TMode & KERNEL_DYNAMIC)) == 0U));
3173
3174 // If hit here: KERNEL_HRT must accompany KERNEL_STATIC or KERNEL_DYNAMIC.
3175 STK_STATIC_ASSERT_N(KERNEL_MODE_HRT_ALONE, (((TMode & KERNEL_HRT) == 0U) ||
3176 ((((TMode & KERNEL_HRT) != 0U)) && (((TMode & KERNEL_STATIC) != 0U) || ((TMode & KERNEL_DYNAMIC) != 0U)))));
3177
3178 // If hit here: KERNEL_TICKLESS is incompatible with KERNEL_HRT. Tickless suppresses the timer,
3179 // which destroys the precise periodicity HRT depends on.
3180 STK_STATIC_ASSERT_N(TICKLESS_HRT_CONFLICT,
3181 (((TMode & KERNEL_TICKLESS) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
3182
3183 // If hit here: KERNEL_TIMESLICE is incompatible with KERNEL_HRT, HRT tasks are scheduled by
3184 // periodicity and Yield() signals job completion.
3185 STK_STATIC_ASSERT_N(TIMESLICE_HRT_CONFLICT,
3186 (((TMode & KERNEL_TIMESLICE) == 0U) || ((TMode & KERNEL_HRT) == 0U)));
3187
3188 // If hit here: KERNEL_TIMESLICE requires a strategy with a sticky GetNext() and OnTaskTimeSlice()
3189 // (TIMESLICE_API == 1), e.g. SwitchStrategyPT32_TS.
3190 STK_STATIC_ASSERT_N(TIMESLICE_STRATEGY_UNSUPPORTED,
3191 (((TMode & KERNEL_TIMESLICE) == 0U) || (TStrategy::TIMESLICE_API != 0)));
3192
3193 // If hit here: Strategy which supports Priority Inheritance API must also support Weight API.
3194 STK_STATIC_ASSERT_N(KERNEL_MODE_MUST_BE_SET, (TStrategy::PRIORITY_INHERITANCE_API && TStrategy::WEIGHT_API) ||
3195 !TStrategy::PRIORITY_INHERITANCE_API);
3196
3201
3216
3232
3239
3240 KernelService m_service;
3241 TPlatform m_platform;
3242 TStrategy m_strategy;
3243 KernelTask *m_task_now;
3245 SleepTrapStack m_sleep_trap[1];
3248 volatile uint8_t m_request;
3251
3253 // FSM_EVENT_SWITCH FSM_EVENT_SLEEP FSM_EVENT_WAKE FSM_EVENT_EXIT
3258 };
3259
3261};
3262
3263} // namespace stk
3264
3265#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...
Fixed-priority preemptive strategy with ThreadX-style Preemption-Threshold and optional per-task time...
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:160
@ 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:234
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:137
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:138
@ WAIT_RESULT_CANCELED
The wait was cancelled by another task via IKernel::CancelTaskWait(), independent of signal/timeout.
Definition stk_common.h:141
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:140
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:139
@ PERIODICITY_DEFAULT
Default periodicity (microseconds), 1 millisecond.
Definition stk_common.h:107
@ PERIODICITY_MAX
Maximum periodicity (microseconds), 99 milliseconds (note: this value is the highest working on a rea...
Definition stk_common.h:106
int64_t Ticks
Ticks value.
Definition stk_common.h:175
@ KERNEL_PANIC_BAD_MODE
Kernel is in bad/unsupported mode for the current operation.
Definition stk_common.h:70
@ KERNEL_PANIC_BAD_STATE
Kernel entered unexpected (bad) state.
Definition stk_common.h:69
@ TASK_STATE_EXITING
Run() has returned, the slot is released on the next tick (KERNEL_DYNAMIC mode only).
Definition stk_common.h:87
@ TASK_STATE_SLEEPING
Sleeping via Sleep()/SleepUntil(), with a finite or an infinite timeout.
Definition stk_common.h:84
@ TASK_STATE_SUSPENDED
Suspended by IKernel::SuspendTask().
Definition stk_common.h:86
@ TASK_STATE_REMOVED
The task is not bound to a kernel slot (never added, or already removed).
Definition stk_common.h:82
@ TASK_STATE_WAITING
Blocked on a synchronization object (IKernelService::Wait). KERNEL_SYNC mode only.
Definition stk_common.h:85
@ TASK_STATE_READY
Runnable: running, or waiting for the CPU.
Definition stk_common.h:83
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:170
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:117
@ SYS_TASK_ID_SLEEP
Sleep trap.
Definition stk_common.h:116
static constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:244
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:759
static constexpr Timeout NO_TIME_SLICE
Time-slice quantum value: no time-slicing for the task (it runs until it blocks, yields or is preempt...
Definition stk_common.h:250
static constexpr Weight NO_WEIGHT
Weight value: weight is not set.
Definition stk_common.h:239
Timeout GetInitialSleepTicks()
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:228
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:222
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:128
@ TRACE_EVENT_SUSPEND
Task suspended via Suspend.
Definition stk_common.h:130
@ TRACE_EVENT_WAIT
Task suspended on a sync object.
Definition stk_common.h:129
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
Definition stk_common.h:97
@ STACK_USER_TASK
Stack of the user task.
Definition stk_common.h:96
@ STACK_EXIT_TRAP
Stack of the Exit trap.
Definition stk_common.h:98
Timeout GetInitialSleepTicks< false >()
Definition stk.h:42
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:41
uint64_t Cycles
Cycles value.
Definition stk_common.h:185
Word TId
Task (thread) id.
Definition stk_common.h:165
int32_t Weight
Weight value (aka priority).
Definition stk_common.h:190
@ KERNEL_TELEMETRY
Enable introspection functions for diagnostics / telemetry (see IKernel::GetTaskState).
Definition stk_common.h:53
@ KERNEL_TIMESLICE
Time-slicing: running task is rotated behind its same-priority peers when its quantum (see ITask::Get...
Definition stk_common.h:52
@ 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:2197
bool UpdateFsmState(Stack *&idle, Stack *&active)
Update FSM state.
Definition stk.h:2936
KernelTask * AllocateNewTask(ITask *user_task)
Allocate new instance of KernelTask.
Definition stk.h:1888
void RequestAddTask(ITask *const user_task)
Request to add new task.
Definition stk.h:1974
void OnTaskExit(Stack *stack) override
Called from the Thread process when task finished (its Run function exited by return).
Definition stk.h:2415
EFsmState
Finite-state machine (FSM) state. Encodes what the kernel is currently doing between two consecutive ...
Definition stk.h:1815
KernelTask * FindTaskByStack(const Stack *stack)
Find kernel task by the bound Stack instance.
Definition stk.h:2046
KernelTask TaskStorageType[TASKS_MAX]
KernelTask array type used as a storage for the KernelTask instances.
Definition stk.h:3200
~Kernel()=default
Destructor.
Weight OnSetWeight(TId tid, Weight weight)
Definition stk.h:2558
bool OnTick(Stack *&idle, Stack *&active, Timeout &ticks) override
Process one scheduler tick. Called from the platform timer/tick ISR.
Definition stk.h:2224
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:2443
void OnSuspend(bool suspended) override
Called from the Thread process to suspend scheduling.
Definition stk.h:2513
void ScheduleTaskRemoval(ITask *user_task) override
Schedule task removal from scheduling (exit).
Definition stk.h:1464
EFsmState GetNewFsmState(KernelTask *&next)
Get new FSM state.
Definition stk.h:2925
void RemoveTask(ITask *user_task) override
Remove a previously added task from the kernel when it is not started.
Definition stk.h:1439
StackMemoryWrapper< STACK_SIZE_MIN > ExitTrapStackMemory
Stack memory wrapper type for the exit trap.
Definition stk.h:112
void OnRestoreWeight(TId tid, ISyncObject *sobj)
Definition stk.h:2634
void OnStart(Stack *&active) override
Called by platform driver immediately after a scheduler start (first tick).
Definition stk.h:2132
bool StateWake(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Wakes up after sleeping.
Definition stk.h:3026
Timeout OnSetTimeSlice(TId tid, Timeout ticks)
Definition stk.h:2585
KernelTask * FindTaskBySP(Word SP)
Find kernel task for a Stack Pointer (SP).
Definition stk.h:2067
void InitTraps()
Initialize stack of the traps.
Definition stk.h:1854
static constexpr bool IsHrtMode()
Definition stk.h:3158
void AddTask(ITask *user_task) override
Register task for a soft real-time (SRT) scheduling.
Definition stk.h:1375
static constexpr bool IsTimesliceMode()
Definition stk.h:3161
ISyncObject::ListHeadType SyncObjectList
Intrusive list of active ISyncObject instances registered with this kernel. Each sync object in this ...
Definition stk.h:3238
EFsmEvent
Finite-state machine (FSM) event. Computed by FetchNextEvent() each tick based on strategy output and...
Definition stk.h:1829
StackMemoryWrapper<((32U))> SleepTrapStackMemory
Stack memory wrapper type for the sleep trap.
Definition stk.h:106
size_t EnumerateKernelTasks(ArrayView< IKernelTask * > tasks) override
Enumerate kernel tasks.
Definition stk.h:1699
static constexpr bool IsSyncMode()
Definition stk.h:3159
KernelTask * FindTaskByUserTask(const ITask *user_task)
Find kernel task by the bound ITask instance (Non-const version).
Definition stk.h:2028
static bool IsValidFsmState(EFsmState state)
Check if FSM state is valid.
Definition stk.h:1847
static constexpr bool IsTelemetryMode()
Definition stk.h:3162
void OnInheritWeight(TId tid, Weight weight)
Definition stk.h:2538
void ResumeTask(ITask *user_task) override
Resume task.
Definition stk.h:1551
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:2347
void Start() override
Start the scheduler. This call does not return until all tasks have exited (KERNEL_DYNAMIC mode) or i...
Definition stk.h:1755
static constexpr bool IsTicklessMode()
Definition stk.h:3160
void RemoveTask(KernelTask *task)
Remove kernel task.
Definition stk.h:2107
void CancelTaskWait(ITask *user_task) override
Cancel task's in-progress wait on a synchronization object.
Definition stk.h:1579
void AddKernelTask(KernelTask *task)
Add kernel task to the scheduling strategy.
Definition stk.h:1928
EKernelState GetState() const override
Get kernel state.
Definition stk.h:1799
ERequest
Bitmask flags for pending inter-task requests that must be processed by the kernel on the next tick (...
Definition stk.h:119
bool StateExit(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Exits from scheduling.
Definition stk.h:3089
static TaskPtr FindTaskByUserTaskImpl(const ITask *user_task, Storage &task_storage)
Definition stk.h:2006
KernelTask * m_task_now
Currently executing task, or nullptr before Start() or after all tasks exit.
Definition stk.h:3243
IPlatform * GetPlatform() override
Get platform driver instance owned by this kernel.
Definition stk.h:1790
void AllocateAndAddNewTask(ITask *user_task)
Allocate new instance of KernelTask and add it into the scheduling process.
Definition stk.h:1945
void OnTaskSwitch(Word caller_SP) override
Called by Thread process (via IKernelService::SwitchToNext) to switch to a next task.
Definition stk.h:2299
void Initialize(uint32_t resolution_us=PERIODICITY_DEFAULT) override
Initialize kernel.
Definition stk.h:1338
TPlatform m_platform
Platform driver (SysTick, PendSV, context switch implementation).
Definition stk.h:3241
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:1960
TId OnGetTid(Word caller_SP) override
Called from the Thread process when for getting task/thread id of the process.
Definition stk.h:2505
size_t EnumerateTasks(ArrayView< ITask * > user_tasks) override
Enumerate user tasks.
Definition stk.h:1725
void ProcessTaskPendingSleep(KernelTask *const task)
Definition stk.h:2668
Timeout UpdateTasks(const Timeout elapsed_ticks)
Update tasks (sleep, requests).
Definition stk.h:2652
void ScheduleAddTask()
Signal the kernel to process a pending AddTask request on the next tick.
Definition stk.h:3124
bool GetTaskState(ITask *user_task, TaskStateInfo &info) const override
Get a snapshot of the kernel-side state of a task.
Definition stk.h:1618
const KernelTask * FindTaskByUserTask(const ITask *user_task) const
Find kernel task by the bound ITask instance (Const version).
Definition stk.h:2037
bool IsInitialized() const
Check whether Initialize() has been called and completed successfully.
Definition stk.h:3118
static constexpr bool IsDynamicMode()
Definition stk.h:3157
bool OnForceContextSwitch(TId id, Stack *&idle, Stack *&active)
Called when task state change forces a context switch (Sleep, SleepUntil, Wait).
Definition stk.h:2260
void ProcessTaskPendingYield(KernelTask *const task)
Definition stk.h:2679
ITaskSwitchStrategy * GetSwitchStrategy() override
Get task-switching strategy instance owned by this kernel.
Definition stk.h:1795
bool StateSwitch(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Switches contexts.
Definition stk.h:2979
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:1414
Kernel()
Construct the kernel with all storage zero-initialized, m_request cleared to REQ_NONE,...
Definition stk.h:1305
void UpdateTaskRequest()
Update pending task requests.
Definition stk.h:2850
bool StateSleep(KernelTask *now, KernelTask *next, Stack *&idle, Stack *&active)
Enters into a sleeping mode.
Definition stk.h:3058
Timeout UpdateTaskState(const Timeout elapsed_ticks)
Update task state: process removals, deliver sleep/wake notifications, advance sleep timers,...
Definition stk.h:2715
void UpdateSyncObjects(const Timeout elapsed_ticks)
Update synchronization objects.
Definition stk.h:2831
static constexpr bool IsStaticMode()
Definition stk.h:3156
void UpdateTimeslice(const Timeout elapsed_ticks)
Charge the running task and rotate it behind its same-priority peers when its slice expires.
Definition stk.h:2607
bool IsStarted() const
Check whether scheduler is currently running.
Definition stk.h:1782
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:2376
void SuspendTask(ITask *user_task, bool &suspended) override
Suspend task.
Definition stk.h:1494
EFsmEvent FetchNextEvent(KernelTask *&next)
Fetch next event for the FSM.
Definition stk.h:2884
Internal per-slot kernel descriptor that wraps a user ITask instance.
Definition stk.h:136
Weight GetBaseWeight() const override
Get base scheduling weight from the user task, ignoring priority inheritance.
Definition stk.h:273
Weight GetCurrentWeight() const override
Get current (run-time) scheduling weight.
Definition stk.h:310
KernelTask()
Construct a free (unbound) task slot. All fields set to zero/null.
Definition stk.h:170
void ScheduleSleep(Timeout ticks)
Put the task into a sleeping state for the specified number of ticks.
Definition stk.h:968
void BusyWaitWhileYielding(Kernel *const kernel) const
Request a context switch and wait until the kernel consumes the pending yield.
Definition stk.h:1009
Timeout GetSleepTicks(Timeout sleep_ticks)
Definition stk.h:399
TId GetTid() const
Get task identifier.
Definition stk.h:213
void HrtOnSwitchedOut()
Called when task is switched out from the scheduling process.
Definition stk.h:909
EStateFlags
Bitmask of transient state flags. Set by the task or the kernel and consumed (cleared) during UpdateT...
Definition stk.h:144
@ STATE_REMOVE_PENDING
Task returned from its Run function; slot will be freed on the next tick (KERNEL_DYNAMIC only).
Definition stk.h:146
@ STATE_SUSPENDED
Task is suspended by SuspendTask.
Definition stk.h:149
@ STATE_YIELD_PENDING
Task called Yield() and the strategy handled it via OnTaskYield() (task stays runnable); cleared by t...
Definition stk.h:150
@ STATE_WAKE_PENDING
Task wake is pending (see Wake).
Definition stk.h:148
@ STATE_SLEEP_PENDING
Task called Sleep/SleepUntil/Yield; strategy's OnTaskSleep() will be invoked on the next tick (sleep-...
Definition stk.h:147
@ STATE_NONE
No pending state flags.
Definition stk.h:145
Timeout GetHrtPeriodicity() const override
Get HRT scheduling periodicity.
Definition stk.h:330
friend class Kernel
Definition stk.h:137
bool HrtIsDeadlineMissed(Timeout duration) const
Check if deadline missed.
Definition stk.h:954
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:1043
void ScheduleRemoval(Kernel *const kernel)
Schedule the removal of the task from the kernel on next tick.
Definition stk.h:805
Stack m_stack
Stack descriptor (SP register value + access mode + optional tid).
Definition stk.h:1040
void SetBaseWeight(Weight weight)
Override the base weight at run-time (see IKernelService::SetWeight).
Definition stk.h:293
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:720
~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:1045
void HrtHardFailDeadline(IPlatform *platform)
Hard-fail HRT task when it missed its deadline.
Definition stk.h:931
Weight m_base_weight[STK_ALLOCATE_COUNT< TStrategy::WEIGHT_API, 1U, 1U, 0U >::Value]
Run-time override of ITask::GetWeight() (NO_WEIGHT = not overridden). Zero-size for unweighted strate...
Definition stk.h:1046
void HrtInit(Timeout periodicity_tc, Timeout deadline_tc, Timeout start_delay_tc)
Initialize task with HRT info.
Definition stk.h:882
volatile uint32_t m_state
Bitmask of EStateFlags. Written by task thread, read/cleared by kernel tick.
Definition stk.h:1041
bool IsSleepInfinite() const
Check whether this task is currently sleeping infinitely.
Definition stk.h:208
ITask * m_user
Bound user task, or NULL when slot is free.
Definition stk.h:1039
Timeout GetHrtRelativeDeadline() const override
Get remaining HRT deadline (ticks left before the deadline expires).
Definition stk.h:378
void SetCurrentWeight(Weight weight) override
Update the run-time scheduling weight (weighted strategies only).
Definition stk.h:236
void BusyWaitWhileSleeping(Kernel *kernel) const
Block further execution of the task's context while in sleeping state.
Definition stk.h:1024
Stack GetUserStack() const override
Get stack descriptor for this task slot.
Definition stk.h:193
bool IsBusy() const
Check whether this slot is bound to a user task.
Definition stk.h:198
bool IsSleeping() const override
Check whether this task is currently sleeping (waiting for a tick or a wake event).
Definition stk.h:203
const ITask * GetUserTask() const
Get bound user task (const).
Definition stk.h:188
Stack * GetUserStackPtr()
Get pointer to user Stack.
Definition stk.h:1037
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:1044
void HrtOnWorkCompleted()
Called when task process called IKernelService::SwitchToNext to inform Kernel that work is completed.
Definition stk.h:945
void Wake() override
Wake this task on the next scheduling tick.
Definition stk.h:219
Weight GetWeight() const override
Get static scheduling weight from the user task.
Definition stk.h:247
volatile Timeout m_time_sleep
Sleep countdown: negative while sleeping (absolute value = ticks remaining), zero when awake.
Definition stk.h:1042
bool IsPendingRemoval() const
Check if task is pending removal.
Definition stk.h:839
Timeout GetHrtDeadline() const override
Get absolute HRT deadline (ticks elapsed since task was activated).
Definition stk.h:353
void Unbind()
Reset this slot to the free (unbound) state, clearing all scheduling metadata.
Definition stk.h:765
void HrtOnSwitchedIn()
Called when task is switched into the scheduling process.
Definition stk.h:904
bool IsMemoryOfSP(Word SP) const
Check if Stack Pointer (SP) belongs to this task.
Definition stk.h:844
TsInfo m_ts[STK_ALLOCATE_COUNT< TMode, KERNEL_TIMESLICE, 1U, 0U >::Value]
Time-slice metadata. Zero-size (no memory) if KERNEL_TIMESLICE is not set.
Definition stk.h:1048
ITask * GetUserTask() override
Get bound user task.
Definition stk.h:183
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:1047
void ScheduleYield()
Mark the task as yielding (strategy handled Yield() without sleeping the task).
Definition stk.h:991
Payload for an in-flight AddTask() request issued by a running task.
Definition stk.h:162
ITask * user_task
User task to add. Must remain valid for the lifetime of its kernel slot.
Definition stk.h:163
Per-task soft real-time (SRT) metadata.
Definition stk.h:446
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:452
AddTaskRequest * add_task_req
Definition stk.h:462
Per-task Hard Real-Time (HRT) scheduling metadata.
Definition stk.h:470
void Clear()
Clear all fields, ready for slot re-use or re-activation.
Definition stk.h:476
volatile bool done
Set to true when the task signals work completion (via Yield() or on exit). Triggers HrtOnSwitchedOut...
Definition stk.h:487
Timeout deadline
Maximum allowed active duration in ticks (relative to switch-in). Exceeding this triggers OnDeadlineM...
Definition stk.h:485
Timeout periodicity
Activation period in ticks: the task is re-activated every this many ticks.
Definition stk.h:484
Timeout duration
Ticks spent in the active (non-sleeping) state in the current period. Incremented by UpdateTaskState(...
Definition stk.h:486
Per-task time-slice (KERNEL_TIMESLICE) metadata.
Definition stk.h:495
void Clear()
Clear all fields, ready for slot re-use.
Definition stk.h:501
Timeout quantum
Configured slice (ticks), NO_TIME_SLICE if time-slicing is disabled for the task.
Definition stk.h:514
void Reload()
Restart the current slice.
Definition stk.h:509
volatile Timeout left
Ticks left in the current slice. Written by the tick handler and, under the critical section,...
Definition stk.h:515
Concrete implementation of IWaitObject, embedded in each KernelTask slot.
Definition stk.h:525
bool IsWaiting() const
Check if busy with waiting.
Definition stk.h:559
EWaitResult GetWaitResult() const
Get wait result.
Definition stk.h:565
EState GetState() const override
Get current state.
Definition stk.h:554
Timeout m_time_wait
Ticks remaining until timeout. Decremented each tick; WAIT_INFINITE means no timeout.
Definition stk.h:712
void Wake(bool timeout) override
Wake the waiting task (called by ISyncObject when it signals).
Definition stk.h:598
~WaitObject()=default
Destructor.
void Cancel()
Cancel an in-progress wait and wake the owning task early.
Definition stk.h:682
bool Tick(Timeout elapsed_ticks) override
Advance the timeout countdown by a number of ticks.
Definition stk.h:617
void CancelNoWake()
Cancel an in-progress wait without waking the owning task.
Definition stk.h:660
void SetupWait(ISyncObject *sync_obj, Timeout timeout)
Configure and arm this wait object for a new wait operation.
Definition stk.h:642
TId GetTid() const override
Get the TId of the task that owns this wait object.
Definition stk.h:548
void ClearState()
Clear state.
Definition stk.h:586
bool CancelIfWaiting()
Cancel an in-progress wait and wake the owning task early if was waiting.
Definition stk.h:699
volatile EState m_state
State of the object, see WaitObject::EState.
Definition stk.h:713
ISyncObject * m_sync_obj
Sync object this wait is registered with, or NULL when not waiting.
Definition stk.h:711
KernelTask * m_task
Back-pointer to the owning KernelTask. Set once at construction; never changes.
Definition stk.h:710
Payload stored in the sync object's kernel-side list entry while a task is waiting.
Definition stk.h:541
ISyncObject * sync_obj
Sync object whose Tick() will be called each kernel tick.
Definition stk.h:542
KernelService()
Construct an uninitialized service instance (m_platform = null, m_ticks = 0).
Definition stk.h:1261
Timeout Suspend() override
Suspend scheduling.
Definition stk.h:1167
void SwitchToNext() override
Notify scheduler to switch to the next task (yield).
Definition stk.h:1128
volatile Ticks m_ticks
Global tick counter. Written via hw::WriteVolatile64() by IncrementTick() (ISR context); read via hw:...
Definition stk.h:1289
void Wake(ISyncObject *sobj, bool all) override
Wake one or all tasks currently waiting on a synchronization object.
Definition stk.h:1148
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Definition stk.h:1071
friend class Kernel
Definition stk.h:1060
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
Definition stk.h:1088
Kernel * m_kernel
Pointer to the Kernel.
Definition stk.h:1288
Ticks GetTicks() const override
Get number of ticks elapsed since kernel start.
Definition stk.h:1065
void SleepCancel(TId task_id) override
Cancel sleep of the task.
Definition stk.h:1120
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
Definition stk.h:1180
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
Definition stk.h:1104
void RestoreWeight(TId tid, ISyncObject *sobj) override
Restore weight of the task to the original value.
Definition stk.h:1200
~KernelService()=default
Destructor.
void InheritWeight(TId tid, Weight weight) override
Inherit weight for the task.
Definition stk.h:1192
Cycles GetSysTimerCount() const override
Get system timer count value.
Definition stk.h:1069
uint32_t GetTickResolution() const override
Get number of microseconds in one tick.
Definition stk.h:1067
void Delay(Timeout ticks) override
Delay calling process.
Definition stk.h:1073
Weight SetWeight(TId tid, Weight weight) override
Change the base weight of the task at run-time (replaces ITask::GetWeight() value).
Definition stk.h:1208
TId GetTid() const override
Get thread Id of the currently running task.
Definition stk.h:1063
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:1135
Timeout SetTimeSlice(TId tid, Timeout ticks) override
Change the time-slice quantum of the task at run-time and reload its slice.
Definition stk.h:1233
void IncrementTicks(Ticks advance)
Increment counter by value.
Definition stk.h:1282
void Initialize(Kernel *kernel)
Initialize instance.
Definition stk.h:1274
Storage bundle for the sleep trap: a Stack descriptor paired with its backing memory.
Definition stk.h:3210
SleepTrapStackMemory::MemoryType Memory
Definition stk.h:3211
Memory memory
Backing stack memory array. Size: STK_SLEEP_TRAP_STACK_SIZE elements of Word.
Definition stk.h:3214
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:3213
Storage bundle for the exit trap: a Stack descriptor paired with its backing memory.
Definition stk.h:3226
Memory memory
Backing stack memory array. Size: STACK_SIZE_MIN elements of Word.
Definition stk.h:3230
ExitTrapStackMemory::MemoryType Memory
Definition stk.h:3227
Stack stack
Stack descriptor (SP register value + access mode). Initialized by InitTraps() on every Start().
Definition stk.h:3229
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:277
size_t GetSize() const
Get number of elements in the view.
Definition stk_common.h:317
Snapshot of the kernel-side state of a task, filled in by IKernel::GetTaskState().
Definition stk_common.h:338
ETaskState state
Task state.
Definition stk_common.h:339
ISyncObject * wait_obj
Definition stk_common.h:340
Stack descriptor.
Definition stk_common.h:427
uint32_t access_mode
Bitfield with hardware access mode of the task (see EAccessMode).
Definition stk_common.h:429
TId tid
Task id (see STK_SEGGER_SYSVIEW, STK_MPU_STACK_GUARD).
Definition stk_common.h:440
Interface for a stack memory region.
Definition stk_common.h:448
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:497
EState
State of the WaitObject.
Definition stk_common.h:513
@ STATE_CANCELLED
Wait was cancelled via Cancel() rather than Wake()/timeout.
Definition stk_common.h:518
@ STATE_TIMEOUT
Wait expired due to timeout rather than a Wake() signal.
Definition stk_common.h:517
@ STATE_SIGNALED
Wake signaled.
Definition stk_common.h:516
@ STATE_WAIT
Wait is active.
Definition stk_common.h:515
Synchronization object interface.
Definition stk_common.h:612
virtual void WakeAll()=0
Wake all tasks currently in the wait list.
DLEntryType ListEntryType
List entry type of ISyncObject elements.
Definition stk_common.h:625
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:620
static void AddWaitObject(IWaitObject::ListHeadType &wlist, IWaitObject *wobj)
Called by kernel when a new task starts waiting on this event.
Definition stk_common.h:631
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:351
Interface for mutex synchronization primitive.
Definition stk_common.h:766
virtual void Unlock()=0
Unlock the mutex.
virtual void Lock()=0
Lock the mutex.
Interface for a user task.
Definition stk_common.h:824
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:921
virtual Timeout GetTimeSlice() const
Get time-slice quantum of the task (ticks). KERNEL_TIMESLICE only.
Definition stk_common.h:937
Scheduling-strategy-facing interface for a kernel task slot.
Definition stk_common.h:963
Interface for a platform driver.
virtual void ProcessHardFault()=0
Cause a hard fault of the system.
Interface for a back-end event handler.
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 & GetMutableWaitList(ISyncObject *sobj)
Access helper to the mutable IWaitObject::GetWaitList().
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:193
StackMemoryDef< _StackSize >::Type MemoryType
Definition stk_helper.h:198
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.