SuperTinyKernel™ RTOS 1.06.0
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::hw Namespace Reference

Hardware Abstraction Layer (HAL) for architecture-specific operations. More...

Classes

class  CriticalSection
 Nestable, SMP-safe critical section that combines local interrupt masking with a global cross-core spinlock. More...
class  SpinLock
 Atomic busy-wait lock used as the global cross-core synchronisation primitive inside CriticalSection. More...
class  HiResClock
 High-resolution clock for high-precision measurements. More...

Functions

template<typename T>
__stk_forceinline Word PtrToWord (T *ptr) noexcept
 Cast a pointer to a CPU register-width integer.
template<typename T>
__stk_forceinline T * WordToPtr (Word value) noexcept
 Cast a CPU register-width integer back to a pointer.
bool IsInsideISR ()
 Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Word GetTls ()
 Read raw thread-pointer (TP) register used as per-task TLS storage.
void SetTls (Word tp)
 Write raw thread-pointer (TP) register used as per-task TLS storage.
template<class _TyTls>
__stk_forceinline _TyTls * GetTlsPtr ()
 Type-safe wrapper around GetTls() that casts the raw TP value to a typed pointer.
template<class _TyTls>
__stk_forceinline void SetTlsPtr (const _TyTls *tp)
 Type-safe wrapper around SetTls() that stores a typed pointer as the raw TP value.
template<typename T>
__stk_forceinlineReadVolatile64 (volatile const T *addr)
 Atomically read a 64-bit volatile value.
template<typename T>
__stk_forceinline void WriteVolatile64 (volatile T *addr, T value)
 Atomically write a 64-bit volatile value.

Detailed Description

Hardware Abstraction Layer (HAL) for architecture-specific operations.

This namespace contains low-level functions that interface directly with the CPU registers and hardware state. Implementations live in the architecture back-end headers included above and are typically written in assembly or using compiler intrinsics for maximum performance and minimum latency.

See also
IsInsideISR, GetTlsPtr, SetTlsPtr, CriticalSection, SpinLock, ReadVolatile64, WriteVolatile64

Function Documentation

◆ GetTls()

Word stk::hw::GetTls ( )

Read raw thread-pointer (TP) register used as per-task TLS storage.

Returns
Current TP register value as a Word.
Note
Architecture-specific. On ARM Cortex-M the kernel stores the TLS pointer in a dedicated register or memory location; on RISC-V it is the tp register.
Use GetTlsPtr<T>() for a type-safe wrapper that returns a typed pointer.
Warning
ISR-unsafe in the sense that the TP register holds the current task's context; reading it from an ISR will return the interrupted task's TLS, not an ISR-specific one.

Referenced by GetTlsPtr().

Here is the caller graph for this function:

◆ GetTlsPtr()

template<class _TyTls>
__stk_forceinline _TyTls * stk::hw::GetTlsPtr ( )

Type-safe wrapper around GetTls() that casts the raw TP value to a typed pointer.

Template Parameters
_TyTlsThe type pointed to by the TLS register (typically the per-task kernel context struct).
Returns
Pointer to the current task's TLS object, or nullptr if TLS has not been set.
Note
Equivalent to reinterpret_cast<_TyTls*>(GetTls()). Prefer this over calling GetTls() directly to avoid scattered reinterpret_casts throughout the codebase.

Definition at line 158 of file stk_arch.h.

159{
161}
__stk_forceinline T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:111
Word GetTls()
Read raw thread-pointer (TP) register used as per-task TLS storage.

References __stk_forceinline, GetTls(), and WordToPtr().

Referenced by stk_tls_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsInsideISR()

bool stk::hw::IsInsideISR ( )

Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).

Returns
true if called from an ISR context; false if called from a normal task/thread context.
Note
Used as a guard in all ISR-unsafe kernel functions (Sleep, Delay, Yield, GetTid, etc.) to catch accidental calls from interrupt context that would deadlock the scheduler.
ISR-safe itself: may be called from any context.

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::Delay(), IsIrqContext(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::Sleep(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::SleepUntil(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::SwitchToNext(), stk::sync::Mutex::TimedLock(), stk::sync::SpinLock::Unlock(), stk::sync::ConditionVariable::Wait(), stk::sync::Event::Wait(), stk::sync::EventFlags::Wait(), and stk::sync::Semaphore::Wait().

Here is the caller graph for this function:

◆ PtrToWord()

template<typename T>
__stk_forceinline Word stk::hw::PtrToWord ( T * ptr)
noexcept

Cast a pointer to a CPU register-width integer.

Template Parameters
TThe type of the object pointed to.
Parameters
[in]ptrThe pointer to be converted.
Returns
The numeric value of the pointer as a Word.
Note
This operation is used to store pointers within task context structures or stack frames where raw register values are required.
MISRA deviation: [STK-DEV-001] Rule 5-2-7 (reinterpret_cast). This is a mechanical necessity for low-level kernel operations where the hardware requires integral values for address registers.
See also
WordToPtr

Definition at line 94 of file stk_arch.h.

95{
96 STK_STATIC_ASSERT(sizeof(Word) == sizeof(T *));
97 return reinterpret_cast<Word>(ptr);
98}
#define STK_STATIC_ASSERT(X)
Compile-time assertion. Produces a compilation error if X is false.
Definition stk_defs.h:367
uintptr_t Word
Native processor word type.
Definition stk_common.h:113

References __stk_forceinline, and STK_STATIC_ASSERT.

Referenced by stk::Task< _StackSize, _AccessMode >::GetId(), stk::TaskW< _Weight, _StackSize, _AccessMode >::GetId(), stk::time::TimerHost::TimerWorkerTask::GetId(), StkThread::GetId(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelTask::GetTid(), stk::PlatformContext::InitStackMemory(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelTask::IsMemoryOfSP(), and SetTlsPtr().

Here is the caller graph for this function:

◆ ReadVolatile64()

template<typename T>
__stk_forceinline T stk::hw::ReadVolatile64 ( volatile const T * addr)

Atomically read a 64-bit volatile value.

Template Parameters
TMust be exactly 8 bytes wide and at least 4-byte aligned (enforced by static assertions).
Parameters
[in]addrPointer to the volatile 64-bit memory location.
Returns
Consistent 64-bit snapshot of the value at addr.
Note
On 64-bit architectures a single aligned load is inherently atomic, the value is read directly with no additional protocol.
On 32-bit architectures uses a lock-free hi-lo retry protocol compatible with WriteVolatile64: reads the high half, then the low half, then re-reads the high half. If the high half changed between the first and second read, a tick occurred between the two 32-bit loads and the pair is retried until a consistent snapshot is obtained. Requires that WriteVolatile64 writes hi before lo (which it does).
Requires a single writer that uses WriteVolatile64. Safe with multiple concurrent readers. Not C++ memory-model compliant, intended for bare-metal embedded use only.
MISRA deviation: [STK-DEV-002] Rule 5-2-7, 5-0-15. Required for lock-free 64-bit I/O on 32-bit architectures using a Hi-Lo retry protocol.
Warning
Not safe for read-modify-write operations. Use only for polling a value written atomically by a single producer.
See also
WriteVolatile64

Definition at line 357 of file stk_arch.h.

358{
359 STK_STATIC_ASSERT_N(sz, sizeof(T) == 8); // only 64-bit types permitted
360 STK_STATIC_ASSERT_N(al, alignof(T) >= 4); // type must be at least 4-byte aligned
361
362 if (sizeof(void *) == 8) // 64-bit arch: aligned 64-bit load is inherently atomic
363 {
364 return (*addr);
365 }
366 else
367 {
368 // 32-bit arch: split the 64-bit address into two 32-bit halves.
369 // Writer always updates hi before lo (see WriteVolatile64), so if hi is
370 // the same before and after reading lo, no write straddled the two reads.
371 volatile const uint32_t *plo = &((volatile const uint32_t *)addr)[STK_ENDIAN_IDX_LO];
372 volatile const uint32_t *phi = &((volatile const uint32_t *)addr)[STK_ENDIAN_IDX_HI];
373
374 uint32_t hi, lo;
375 do
376 {
377 hi = (*phi);
378 __stk_full_memfence();
379
380 lo = (*plo);
381 __stk_full_memfence();
382 }
383 while (hi != (*phi)); // hi changed: a write occurred during the read; retry
384
385 return ((uint64_t)hi << 32) | lo;
386 }
387}
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:359
#define STK_ENDIAN_IDX_LO
Array index of the low 32-bit word when a 64-bit value is viewed as uint32_t[2].
Definition stk_defs.h:503
#define STK_ENDIAN_IDX_HI
Array index of the high 32-bit word when a 64-bit value is viewed as uint32_t[2].
Definition stk_defs.h:502

References __stk_forceinline, STK_ENDIAN_IDX_HI, STK_ENDIAN_IDX_LO, and STK_STATIC_ASSERT_N.

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::GetTicks(), and stk::time::TimerHost::GetTimeNow().

Here is the caller graph for this function:

◆ SetTls()

void stk::hw::SetTls ( Word tp)

Write raw thread-pointer (TP) register used as per-task TLS storage.

Parameters
[in]tpNew TP value to store.
Note
Called by the scheduler during every context switch to update the register to the incoming task's TLS pointer. Not intended for direct use in application code; use SetTlsPtr<T>() instead.

Referenced by SetTlsPtr().

Here is the caller graph for this function:

◆ SetTlsPtr()

template<class _TyTls>
__stk_forceinline void stk::hw::SetTlsPtr ( const _TyTls * tp)

Type-safe wrapper around SetTls() that stores a typed pointer as the raw TP value.

Template Parameters
_TyTlsThe type pointed to by the TLS register (typically the per-task kernel context struct).
Parameters
[in]tpPointer to the new task's TLS object.
Note
Equivalent to SetTls(reinterpret_cast<Word>(tp)). Called by the scheduler during context switches to install the incoming task's TLS pointer.

Definition at line 170 of file stk_arch.h.

171{
173}
__stk_forceinline Word PtrToWord(T *ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:94
void SetTls(Word tp)
Write raw thread-pointer (TP) register used as per-task TLS storage.

References __stk_forceinline, PtrToWord(), and SetTls().

Referenced by stk_tls_set().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WordToPtr()

template<typename T>
__stk_forceinline T * stk::hw::WordToPtr ( Word value)
noexcept

Cast a CPU register-width integer back to a pointer.

Template Parameters
TThe type of the object the resulting pointer will address.
Parameters
[in]valueThe register-width integer (Word) to be converted.
Returns
A pointer of type T* addressing the memory location specified by the value.
Note
This is the inverse of PtrToWord and is primarily used when restoring a task's context from a saved stack frame.
MISRA deviation: [STK-DEV-001] Rule 5-2-7 (reinterpret_cast). Required for restoring pointer types from numeric CPU context structures.
See also
PtrToWord

Definition at line 111 of file stk_arch.h.

112{
113 STK_STATIC_ASSERT(sizeof(Word) == sizeof(T *));
114 return reinterpret_cast<T *>(value);
115}

References __stk_forceinline, and STK_STATIC_ASSERT.

Referenced by GetTlsPtr().

Here is the caller graph for this function:

◆ WriteVolatile64()

template<typename T>
__stk_forceinline void stk::hw::WriteVolatile64 ( volatile T * addr,
T value )

Atomically write a 64-bit volatile value.

Template Parameters
TMust be exactly 8 bytes wide and at least 4-byte aligned (enforced by static assertions).
Parameters
[in]addrPointer to the volatile 64-bit memory location.
[in]valueValue to write.
Note
On 64-bit architectures a single aligned store is inherently atomic.
On 32-bit architectures the value is split into two 32-bit half-writes. The high half is always written before the low half. This ordering is the contractual invariant that ReadVolatile64 depends on to detect a mid-write tear: if a reader observes a changed high half, it knows a write occurred and retries. Breaking this order (writing lo before hi) will corrupt concurrent reads.
A full memory fence is emitted between the two half-writes to prevent the CPU from reordering the stores.
ISR-safe: does not use a critical section.
MISRA deviation: [STK-DEV-002] Rule 5-2-7, 5-0-15. Required for lock-free 64-bit I/O on 32-bit architectures using a Hi-Lo retry protocol.
Warning
Supports only a single writer at a time. Concurrent writers on the same address will corrupt the value. Not safe for read-modify-write operations (e.g. increment); the caller must ensure exclusive write access by other means.
Not C++ memory-model compliant; intended for bare-metal embedded use only.
See also
ReadVolatile64

Definition at line 411 of file stk_arch.h.

412{
413 STK_STATIC_ASSERT_N(sz, sizeof(T) == 8); // only 64-bit types permitted
414 STK_STATIC_ASSERT_N(al, alignof(T) >= 4); // type must be at least 4-byte aligned
415
416 if (sizeof(void *) == 8) // 64-bit arch: aligned 64-bit store is inherently atomic
417 {
418 (*addr) = value;
419 }
420 else
421 {
422 volatile uint32_t *plo = &((volatile uint32_t *)addr)[STK_ENDIAN_IDX_LO];
423 volatile uint32_t *phi = &((volatile uint32_t *)addr)[STK_ENDIAN_IDX_HI];
424
425 // Write hi first: ReadVolatile64 reads hi twice and retries if it changed,
426 // so writing hi before lo ensures readers can detect a torn write.
427 (*phi) = (uint32_t)(value >> 32);
428 __stk_full_memfence();
429
430 (*plo) = (uint32_t)value;
431 }
432}

References __stk_forceinline, STK_ENDIAN_IDX_HI, STK_ENDIAN_IDX_LO, and STK_STATIC_ASSERT_N.

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::IncrementTicks(), and stk::time::TimerHost::UpdateTime().

Here is the caller graph for this function: