SuperTinyKernel™ RTOS 1.07.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_arch_x86-win32.cpp
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// note: If missing, this header must be customized (get it in the root of the source folder) and
11// copied to the /include folder manually.
12#include "stk_config.h"
13
14#ifdef _STK_ARCH_X86_WIN32
15
16#include "stk_arch.h"
18
19using namespace stk;
20
21#define WIN32_LEAN_AND_MEAN
22#include <windows.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <assert.h>
26#include <list>
27#include <vector>
28
29using namespace stk;
30
31#ifndef WINAPI
32#define WINAPI __stdcall
33#endif
34
35typedef UINT MMRESULT;
36typedef MMRESULT (WINAPI * timeBeginPeriodF)(UINT uPeriod);
37static timeBeginPeriodF timeBeginPeriod = nullptr;
38
39#define STK_X86_WIN32_CRITICAL_SECTION CRITICAL_SECTION
40#define STK_X86_WIN32_CRITICAL_SECTION_INIT(SES) ::InitializeCriticalSection(SES)
41#define STK_X86_WIN32_CRITICAL_SECTION_START(SES) ::EnterCriticalSection(SES)
42#define STK_X86_WIN32_CRITICAL_SECTION_END(SES) ::LeaveCriticalSection(SES)
43#define STK_X86_WIN32_MIN_RESOLUTION (1000)
44#define STK_X86_WIN32_GET_SP(STACK) (STACK + 2) // +2 to overcome stack filler check inside Kernel (adjusting to +2 preserves 8-byte alignment)
45#define SLK_UNLOCKED hw::SpinLock::UNLOCKED
46#define SLK_LOCKED hw::SpinLock::LOCKED
47
50static __stk_forceinline bool HW_SpinLockTryLock(volatile LONG &lock)
51{
52 return (InterlockedCompareExchange(
53 reinterpret_cast<volatile LONG *>(&lock), SLK_LOCKED, SLK_UNLOCKED) == SLK_UNLOCKED);
54}
55
58static __stk_forceinline void HW_SpinLockLock(volatile LONG &lock)
59{
60 uint8_t sleep_time = 0;
61 uint32_t timeout = 0xFFFFFF;
62
63test:
64 while (!HW_SpinLockTryLock(lock))
65 {
66 if (--timeout == 0)
67 {
68 // invariant violated: the lock owner exited without releasing
70 }
71
72 for (volatile int32_t spin = 100; (spin != 0); spin--)
73 {
74 __stk_relax_cpu();
75
76 // check if became unlocked then try locking atomically again
77 if (lock == SLK_UNLOCKED)
78 goto test;
79 }
80
81 // avoid priority inversion
82 ::Sleep(sleep_time);
83 sleep_time ^= 1;
84 }
85}
86
89static __stk_forceinline void HW_SpinLockUnlock(volatile LONG &lock)
90{
91 InterlockedExchange(reinterpret_cast<volatile LONG *>(&lock), SLK_UNLOCKED);
92}
93
94struct Win32ScopedCriticalSection
95{
96 STK_X86_WIN32_CRITICAL_SECTION &m_sec;
97
98 explicit Win32ScopedCriticalSection(STK_X86_WIN32_CRITICAL_SECTION &sec) : m_sec(sec)
99 {
100 STK_X86_WIN32_CRITICAL_SECTION_START(&sec);
101 }
102 ~Win32ScopedCriticalSection()
103 {
104 STK_X86_WIN32_CRITICAL_SECTION_END(&m_sec);
105 }
106};
107
108class HiResClockQPC
109{
110 LARGE_INTEGER m_freq;
111 LARGE_INTEGER m_start;
112
113public:
114 explicit HiResClockQPC()
115 {
116 QueryPerformanceFrequency(&m_freq);
117 QueryPerformanceCounter(&m_start);
118 }
119
120 static HiResClockQPC *GetInstance()
121 {
122 // keep declaration function-local to allow compiler stripping it from the binary if
123 // it is unused by the user code
124 static HiResClockQPC clock;
125 return &clock;
126 }
127
128 Cycles GetCycles()
129 {
130 LARGE_INTEGER current;
131 QueryPerformanceCounter(&current);
132
133 // relative cycles since simulation start
134 return static_cast<Cycles>(current.QuadPart - m_start.QuadPart);
135 }
136
137 uint32_t GetFrequency()
138 {
139 return static_cast<uint32_t>(m_freq.QuadPart);
140 }
141};
142
144static struct Context final : public PlatformContext
145{
146 Context()
147 : m_overrider(nullptr),
148 m_sleep_trap(nullptr),
149 m_exit_trap(nullptr),
150 m_winmm_dll(nullptr),
151 m_timer_thread(nullptr),
152 m_tls(TLS_OUT_OF_INDEXES),
153 m_tasks(),
154 m_task_threads(),
155 m_timer_tid(0),
156 #if STK_TICKLESS_IDLE
157 m_sleep_ticks(0),
158 #endif
159 m_cs(),
160 m_csu_nesting(0),
161 m_started(false),
162 m_stop_signal(false)
163 {}
164
165 void Initialize(IPlatform::IEventHandler *handler, IKernelService *service, Stack *exit_trap,
166 uint32_t resolution_us) override
167 {
168 PlatformContext::Initialize(handler, service, exit_trap, resolution_us);
169
170 m_sleep_trap = nullptr; // set by Context::InitStack
171 m_exit_trap = nullptr; // set by Context::InitStack
172 m_winmm_dll = nullptr;
173 m_timer_thread = nullptr;
174 m_started = false;
175 m_stop_signal = false;
176 m_csu_nesting = 0;
177 m_timer_tid = 0;
178 #if STK_TICKLESS_IDLE
179 m_sleep_ticks = 0;
180 #endif
181
182 #if STK_TLS
183 if ((m_tls = TlsAlloc()) == TLS_OUT_OF_INDEXES)
184 {
185 assert(false);
186 return;
187 }
188 #endif
189
190 STK_X86_WIN32_CRITICAL_SECTION_INIT(&m_cs);
191
192 LoadWindowsAPI();
193 }
194
195 virtual ~Context()
196 {
197 #if STK_TLS
198 if (m_tls != TLS_OUT_OF_INDEXES)
199 TlsFree(m_tls);
200 #endif
201
202 UnloadWindowsAPI();
203 }
204
205 void LoadWindowsAPI()
206 {
207 HMODULE winmm = GetModuleHandleA("Winmm");
208 if (winmm == nullptr)
209 m_winmm_dll = winmm = LoadLibraryA("Winmm.dll");
210 assert(winmm != nullptr);
211
212 timeBeginPeriod = (timeBeginPeriodF)GetProcAddress(winmm, "timeBeginPeriod");
213 assert(timeBeginPeriod != nullptr);
214
215 timeBeginPeriod(1);
216 }
217
218 void UnloadWindowsAPI()
219 {
220 if (m_winmm_dll != nullptr)
221 {
222 FreeLibrary(m_winmm_dll);
223 m_winmm_dll = nullptr;
224 }
225 }
226
227 struct TaskContext
228 {
229 TaskContext() : m_task(nullptr), m_stack(nullptr), m_thread(nullptr), m_thread_id(0)
230 {}
231
232 void Initialize(ITask *task, Stack *stack)
233 {
234 m_task = task;
235 m_stack = stack;
236 m_thread = nullptr;
237 m_thread_id = 0;
238
239 InitThread();
240 }
241
242 void InitThread()
243 {
244 // simulate stack size limitation
245 const size_t stack_size = m_task->GetStackSize() * sizeof(Word);
246
247 m_thread = CreateThread(nullptr, stack_size, &OnTaskRun, this, CREATE_SUSPENDED, &m_thread_id);
248 }
249
250 static DWORD WINAPI OnTaskRun(LPVOID param)
251 {
252 ((TaskContext *)param)->m_task->Run();
253 return 0;
254 }
255
256 ITask *m_task;
257 Stack *m_stack;
258 HANDLE m_thread;
259 DWORD m_thread_id;
260 };
261
262 void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task);
263 void ConfigureTime();
264 void StartActiveTask();
265 void CreateTimerThreadAndJoin();
266 void Cleanup();
267 void ProcessTick();
268 void SwitchContext();
269 void SwitchToNext();
270 void Sleep(Timeout ticks);
271 bool SleepUntil(Ticks timestamp);
272 EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout);
273 void Stop();
274 Word GetCallerSP() const;
275 TId GetTid() const;
276
277#if STK_TLS
278 __stk_forceinline Word GetTls()
279 {
280 return hw::PtrToWord(TlsGetValue(m_tls));
281 }
282
283 __stk_forceinline void SetTls(Word tp)
284 {
285 TlsSetValue(m_tls, hw::WordToPtr<void>(tp));
286 }
287#endif
288
289 __stk_forceinline void EnterCriticalSection()
290 {
291 STK_X86_WIN32_CRITICAL_SECTION_START(&m_cs);
292
293 if (m_csu_nesting == 0)
294 {
295 // avoid suspending self
296 if (GetCurrentThreadId() != m_timer_tid)
297 {
298 SuspendThread(m_timer_thread);
299 }
300 }
301
302 // increase nesting count within a limit
303 if (++m_csu_nesting > STK_CS_NESTINGS_MAX)
304 {
305 // invariant violated: exceeded max allowed number of recursions
306 STK_KERNEL_PANIC(KERNEL_PANIC_CS_NESTING_OVERFLOW);
307 }
308 }
309
310 __stk_forceinline void ExitCriticalSection()
311 {
312 STK_ASSERT(m_csu_nesting != 0);
313
314 --m_csu_nesting;
315
316 if (m_csu_nesting == 0)
317 {
318 // suspending self is not supported
319 if (GetCurrentThreadId() != m_timer_tid)
320 {
321 ResumeThread(m_timer_thread);
322 }
323 }
324
325 STK_X86_WIN32_CRITICAL_SECTION_END(&m_cs);
326 }
327
328 IPlatform::IEventOverrider *m_overrider;
329 Stack *m_sleep_trap;
330 Stack *m_exit_trap;
331 HMODULE m_winmm_dll;
332 HANDLE m_timer_thread;
333 DWORD m_tls;
334 std::list<TaskContext *> m_tasks;
335 std::vector<HANDLE> m_task_threads;
336 DWORD m_timer_tid;
337#if STK_TICKLESS_IDLE
338 Timeout m_sleep_ticks;
339#endif
340 STK_X86_WIN32_CRITICAL_SECTION m_cs;
341 uint8_t m_csu_nesting;
342 bool m_started;
343 volatile bool m_stop_signal;
344}
345s_StkPlatformContext[1];
346
348static volatile EKernelPanicId g_LastPanicId = KERNEL_PANIC_NONE;
349
350__stk_attr_noinline // keep out of inlining to preserve stack frame
351__stk_attr_noreturn // never returns - a trap
353{
354 g_LastPanicId = id;
355
356 // spin forever: without a watchdog, a debugger can attach and inspect 'id'
357 for (;;)
358 {
359 __stk_relax_cpu();
360 }
361}
362
363static __stk_forceinline DWORD TicksToMs(uint64_t ticks)
364{
365 return static_cast<DWORD>((ticks * GetContext().m_tick_resolution) / 1000U);
366}
367
368static DWORD WINAPI TimerThread(LPVOID param)
369{
370 (void)param;
371
372 DWORD wait_ms = TicksToMs(1U);
373 GetContext().m_timer_tid = GetCurrentThreadId();
374
375 while (WaitForSingleObject(GetContext().m_timer_thread, wait_ms) == WAIT_TIMEOUT)
376 {
377 if (GetContext().m_stop_signal)
378 {
379 break;
380 }
381
382 GetContext().ProcessTick();
383
384 #if STK_TICKLESS_IDLE
385 wait_ms = TicksToMs(GetContext().m_sleep_ticks);
386 #endif
387 }
388
389 return 0;
390}
391
392void Context::ConfigureTime()
393{
394 // Windows timers are jittery, so make resolution more coarse
395 if (m_tick_resolution < STK_X86_WIN32_MIN_RESOLUTION)
396 {
397 m_tick_resolution = STK_X86_WIN32_MIN_RESOLUTION;
398 }
399
400 // increase precision of ticks to at least 1 ms (although Windows timers will still be quite coarse and have jitter of +1 ms)
401 timeBeginPeriod(1);
402}
403
404void Context::StartActiveTask()
405{
406 STK_ASSERT(m_stack_active != nullptr);
407 TaskContext *active_task = hw::WordToPtr<TaskContext>(m_stack_active->SP);
408 STK_ASSERT(active_task != nullptr);
409
410 ResumeThread(active_task->m_thread);
411}
412
413void Context::CreateTimerThreadAndJoin()
414{
415 m_started = true;
416
417#if STK_TICKLESS_IDLE
418 m_sleep_ticks = 1;
419#endif
420
421 m_handler->OnStart(m_stack_active);
422
423 StartActiveTask();
424
425 // create tick thread with highest priority
426 m_timer_thread = CreateThread(nullptr, 0, &TimerThread, nullptr, 0, nullptr);
427 STK_ASSERT(m_timer_thread != nullptr);
428 SetThreadPriority(m_timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
429
430 while (!m_task_threads.empty())
431 {
432 DWORD result = WaitForMultipleObjects((DWORD)m_task_threads.size(), m_task_threads.data(), FALSE, INFINITE);
433 STK_ASSERT(result != WAIT_TIMEOUT);
434 STK_ASSERT(result != WAIT_ABANDONED);
435 STK_ASSERT(result != WAIT_FAILED);
436
437 Win32ScopedCriticalSection __cs(m_cs);
438
439 uint32_t i = 0;
440 for (std::vector<HANDLE>::iterator itr = m_task_threads.begin(); itr != m_task_threads.end(); ++itr)
441 {
442 if (result == (WAIT_OBJECT_0 + i))
443 {
444 TaskContext *exiting_task = nullptr;
445 for (std::list<TaskContext *>::iterator titr = m_tasks.begin(); titr != m_tasks.end(); ++titr)
446 {
447 if ((*titr)->m_thread == (*itr))
448 {
449 exiting_task = (*titr);
450 break;
451 }
452 }
453 STK_ASSERT(exiting_task != nullptr);
454
455 if (exiting_task != nullptr)
456 {
457 m_handler->OnTaskExit(exiting_task->m_stack);
458 }
459
460 m_task_threads.erase(itr);
461 break;
462 }
463
464 ++i;
465 }
466 }
467
468 // join (never returns to the caller from here unless thread is terminated, see KERNEL_DYNAMIC),
469 // a stop signal is sent by IPlatform::Stop() by the last exiting task
470 if (m_timer_thread != nullptr)
471 {
472 WaitForSingleObject(m_timer_thread, INFINITE);
473 }
474}
475
476void Context::Cleanup()
477{
478 // close thread handles of all tasks
479 for (std::list<TaskContext *>::iterator itr = m_tasks.begin(); itr != m_tasks.end(); ++itr)
480 {
481 if ((*itr)->m_thread != nullptr)
482 {
483 CloseHandle((*itr)->m_thread);
484 (*itr)->m_thread = nullptr;
485 }
486 }
487 m_tasks.clear();
488
489 // close timer thread
490 if (m_timer_thread != nullptr)
491 {
492 CloseHandle(m_timer_thread);
493 m_timer_thread = nullptr;
494 }
495
496 // reset stop signal
497 m_stop_signal = false;
498
499 // notify kernel about a full stop
500 m_handler->OnStop();
501}
502
503void Context::ProcessTick()
504{
505 Win32ScopedCriticalSection __cs(m_cs);
506
507#if STK_TICKLESS_IDLE
508 Timeout ticks = m_sleep_ticks;
509#endif
510
511 if (m_handler->OnTick(m_stack_idle, m_stack_active
512 #if STK_TICKLESS_IDLE
513 , ticks
514 #endif
515 ))
516 {
517 GetContext().SwitchContext();
518 }
519
520#if STK_TICKLESS_IDLE
521 m_sleep_ticks = ticks;
522#endif
523}
524
525void Context::SwitchContext()
526{
527 // suspend Idle thread
528 if ((m_stack_idle != m_sleep_trap) && (m_stack_idle != m_exit_trap))
529 {
530 TaskContext *idle_task = hw::WordToPtr<TaskContext>(m_stack_idle->SP);
531 STK_ASSERT(idle_task != nullptr);
532
533 SuspendThread(idle_task->m_thread);
534 }
535
536 // resume Active thread
537 if (m_stack_active == m_sleep_trap)
538 {
539 #if STK_TICKLESS_IDLE
540 const Timeout sleep_ticks = m_sleep_ticks;
541 #else
542 const Timeout sleep_ticks = 1;
543 #endif
544
545 if ((m_overrider == nullptr) || !m_overrider->OnSleep(sleep_ticks))
546 {
547 // pass
548 }
549 }
550 else
551 if (m_stack_active == GetContext().m_exit_trap)
552 {
553 // pass
554 }
555 else
556 {
557 TaskContext *active_task = hw::WordToPtr<TaskContext>(m_stack_active->SP);
558 STK_ASSERT(active_task != nullptr);
559
560 ResumeThread(active_task->m_thread);
561 }
562}
563
564Word Context::GetCallerSP() const
565{
566 Word caller_sp = 0;
567 DWORD calling_tid = GetCurrentThreadId();
568
569 Win32ScopedCriticalSection __cs(const_cast<STK_X86_WIN32_CRITICAL_SECTION &>(m_cs));
570
571 for (std::list<TaskContext *>::const_iterator itr = m_tasks.begin(), end = m_tasks.end(); itr != end; ++itr)
572 {
573 if ((*itr)->m_thread_id == calling_tid)
574 {
575 caller_sp = hw::PtrToWord(STK_X86_WIN32_GET_SP((*itr)->m_task->GetStack()));
576 break;
577 }
578 }
579
580 // expect to find the calling task inside m_tasks
581 STK_ASSERT(caller_sp != 0);
582
583 return caller_sp;
584}
585
586TId Context::GetTid() const
587{
588 return m_handler->OnGetTid(GetCallerSP());
589}
590
591void Context::SwitchToNext()
592{
593 m_handler->OnTaskSwitch(GetCallerSP());
594}
595
596void Context::Sleep(Timeout ticks)
597{
598 m_handler->OnTaskSleep(GetCallerSP(), ticks);
599}
600
601bool Context::SleepUntil(Ticks timestamp)
602{
603 return m_handler->OnTaskSleepUntil(GetCallerSP(), timestamp);
604}
605
606EWaitResult Context::Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout)
607{
608 return m_handler->OnTaskWait(GetCallerSP(), sync_obj, mutex, timeout);
609}
610
611void Context::Stop()
612{
613 m_stop_signal = true;
614 m_started = false;
615}
616
617void Context::InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task)
618{
619 InitStackMemory(stack_memory);
620
621 Word *const stack_mem = const_cast<Word *>(stack_memory->GetStack());
622 TaskContext *const ctx = reinterpret_cast<TaskContext *>(STK_X86_WIN32_GET_SP(stack_mem));
623
624 switch (stack_type)
625 {
626 case STACK_USER_TASK: {
627 ctx->Initialize(user_task, stack);
628
629 m_tasks.push_back(ctx);
630 m_task_threads.push_back(ctx->m_thread);
631 break; }
632
633 case STACK_SLEEP_TRAP: {
634 GetContext().m_sleep_trap = stack;
635 break; }
636
637 case STACK_EXIT_TRAP: {
638 GetContext().m_exit_trap = stack;
639 break; }
640
641 default: {
642 STK_ASSERT(false);
643 break; }
644 }
645
646 stack->SP = hw::PtrToWord(ctx);
647}
648
649void PlatformX86Win32::Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us,
650 Stack *exit_trap)
651{
652 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
653}
654
656{
657 GetContext().ConfigureTime();
658 GetContext().CreateTimerThreadAndJoin();
659 GetContext().Cleanup();
660}
661
663{
664 GetContext().Stop();
665}
666
668{
669 STK_ASSERT(false); // unsupported
670 return 0;
671}
672
673void PlatformX86Win32::Resume(Timeout elapsed_ticks)
674{
675 STK_ASSERT(false); // unsupported
676}
677
678void PlatformX86Win32::InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task)
679{
680 GetContext().InitStack(stack_type, stack, stack_memory, user_task);
681}
682
684{
685 return GetContext().m_tick_resolution;
686}
687
689{
690 return HiResClockQPC::GetInstance()->GetCycles();
691}
692
694{
695 return HiResClockQPC::GetInstance()->GetFrequency();
696}
697
699{
700 GetContext().SwitchToNext();
701}
702
704{
705 GetContext().Sleep(ticks);
706}
707
709{
710 return GetContext().SleepUntil(timestamp);
711}
712
714{
715 return GetContext().Wait(sync_obj, mutex, timeout);
716}
717
719{
720 GetContext().ProcessTick();
721}
722
724{
725 if ((GetContext().m_overrider == nullptr) || !GetContext().m_overrider->OnHardFault())
726 {
728 }
729}
730
731void PlatformX86Win32::SetEventOverrider(IEventOverrider *overrider)
732{
733 STK_ASSERT(!GetContext().m_started);
734 GetContext().m_overrider = overrider;
735}
736
738{
739 return GetContext().GetCallerSP();
740}
741
743{
744 return GetContext().GetTid();
745}
746
747#if STK_TLS
748Word stk::hw::GetTls()
749{
750 return GetContext().GetTls();
751}
752
753void stk::hw::SetTls(Word tp)
754{
755 return GetContext().SetTls(tp);
756}
757#endif
758
760{
761 return GetContext().m_service;
762}
763
765{
766 STK_UNUSED(is_npriv);
767 GetContext().EnterCriticalSection();
768 return DEFAULT_SESSION;
769}
770
772{
773 STK_UNUSED(is_npriv);
774 GetContext().ExitCriticalSection();
775}
776
778{
779 HW_SpinLockLock(m_lock);
780}
781
783{
784 HW_SpinLockUnlock(m_lock);
785}
786
788{
789 return HW_SpinLockTryLock(m_lock);
790}
791
793{
794 return false;
795}
796
798{
799 return true;
800}
801
803{
804 return HiResClockQPC::GetInstance()->GetCycles();
805}
806
808{
809 return HiResClockQPC::GetInstance()->GetFrequency();
810}
811
812#endif // _STK_ARCH_X86_WIN32
Contains common inventory for platform implementation.
#define GetContext()
Get platform's context.
Hardware Abstraction Layer (HAL) declarations for the stk::hw namespace.
void STK_PANIC_HANDLER_DEFAULT(stk::EKernelPanicId id)
Default panic handler: disable interrupts, record the id, and spin in a tight loop — a defined,...
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:629
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:196
#define STK_CS_NESTINGS_MAX
Maximum allowable recursion depth for critical section entry (default: 16).
Definition stk_defs.h:504
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:430
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
Definition stk_defs.h:276
#define __stk_attr_noreturn
Declares that function never returns to its caller (function prefix).
Definition stk_defs.h:243
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:140
static void Sleep(Timeout tick_count)
Put calling process into a sleep state.
Definition stk_helper.h:452
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:118
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
EStackType
Stack type.
Definition stk_common.h:78
@ 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
uint64_t Cycles
Cycles value.
Definition stk_common.h:165
Word TId
Task (thread) id.
Definition stk_common.h:145
EKernelPanicId
Identifies the source of a kernel panic.
Definition stk_common.h:58
@ KERNEL_PANIC_HRT_HARD_FAULT
Kernel running in KERNEL_HRT mode reported deadline failure of the task.
Definition stk_common.h:63
@ KERNEL_PANIC_NONE
Panic is absent (no fault).
Definition stk_common.h:59
@ KERNEL_PANIC_SPINLOCK_DEADLOCK
Spin-lock timeout expired: lock owner never released.
Definition stk_common.h:60
bool IsPrivilegedContext()
Check if caller context is Privileged.
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:123
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:106
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Base platform context for all platform implementations.
EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
void Stop() override
Stop scheduling.
void Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us, Stack *exit_trap) override
Initialize scheduler's context.
Word GetCallerSP() const override
Get caller's Stack Pointer (SP).
void Start() override
Start scheduling.
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
uint32_t GetTickResolution() const override
Get resolution of the system tick timer in microseconds. Resolution means a number of microseconds be...
void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task) override
Initialize stack memory of the user task.
void ProcessHardFault() override
Cause a hard fault of the system.
void SetEventOverrider(IEventOverrider *overrider) override
Set platform event overrider.
void ProcessTick() override
Process one tick.
Cycles GetSysTimerCount() const override
Get system timer count value.
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
TId GetTid() const override
Get thread Id.
void SwitchToNext() override
Switch to a next task.
Timeout Suspend() override
Suspend scheduling.
static constexpr Session DEFAULT_SESSION
Default session value passed to Enter()/Exit() when the caller does not need to force a specific hand...
Definition stk_arch.h:369
static Session Enter(const Session ses=DEFAULT_SESSION)
Enter a critical section.
uint8_t Session
Opaque session token returned by Enter() and consumed by Exit().
Definition stk_arch.h:362
static void Exit(const Session ses=DEFAULT_SESSION)
Exit a critical section.
bool TryLock()
Attempt to acquire SpinLock in a single non-blocking attempt.
void Lock()
Acquire SpinLock, blocking until it is available.
void Unlock()
Release SpinLock, allowing another thread or core to acquire it.
static uint32_t GetFrequency()
Get clock frequency.
static Cycles GetCycles()
Get number of clock cycles elapsed.
Stack descriptor.
Definition stk_common.h:316
Word SP
Offset 0: Stack Pointer (SP) register.
Definition stk_common.h:317
Interface for a stack memory region.
Definition stk_common.h:334
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Synchronization object interface.
Definition stk_common.h:477
Interface for mutex synchronization primitive.
Definition stk_common.h:610
Interface for a user task.
Definition stk_common.h:667
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
RISC-V specific event handler.