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_defs.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_DEFS_H_
11#define STK_DEFS_H_
12
13#include <cstddef>
14#include <cstdint>
15#include <algorithm>
16#ifdef __ICCARM__
17 #include <intrinsics.h>
18 #if (__IAR_SYSTEMS_ICC__ < 8)
19 #error "Only IAR EWARM 8.0 and higher is supported by STK."
20 #endif
21#endif
22
29#include "stk_config.h"
30
42#ifndef STK_TICKLESS_IDLE
43 #define STK_TICKLESS_IDLE (0U)
44#endif
45
50#ifndef STK_STRICT_COMPLIANCY
51 #define STK_STRICT_COMPLIANCY (0U)
52#endif
53
62#ifndef STK_TICKLESS_USE_ARM_DWT
63 #define STK_TICKLESS_USE_ARM_DWT (1U)
64#endif
65
76#ifndef STK_TICKLESS_TICKS_MAX
77 #define STK_TICKLESS_TICKS_MAX (1000U)
78#endif
79#if STK_TICKLESS_TICKS_MAX > 100000
80 #error "STK_TICKLESS_TICKS_MAX is too large: cpu_ticks_requested may overflow uint32_t."
81#endif
82
98#ifndef STK_TLS
99 #define STK_TLS (0U)
100#endif
101
128#ifndef STK_TLS_PREFER_REGISTER
129 #ifdef _STK_ARCH_RISC_V
130 #define STK_TLS_PREFER_REGISTER (1U)
131 #else
132 #define STK_TLS_PREFER_REGISTER (0U)
133 #endif
134#endif
135
139#ifndef STK_MPU
140 #define STK_MPU (0U)
141#endif
142
146#ifndef STK_MPU_STACK_GUARD
147 #define STK_MPU_STACK_GUARD (0U)
148#endif
149
162#ifndef STK_MPU_TASK_REGIONS
163 #define STK_MPU_TASK_REGIONS (2U)
164#endif
165#ifndef STK_MPU_TASK_REGIONS_NS
166 #define STK_MPU_TASK_REGIONS_NS (STK_MPU_TASK_REGIONS)
167#endif
168#if STK_MPU_STACK_GUARD && \
169 (STK_MPU_TASK_REGIONS != 2U) && (STK_MPU_TASK_REGIONS != 4U) && \
170 (STK_MPU_TASK_REGIONS != 6U) && (STK_MPU_TASK_REGIONS != 8U) && \
171 (STK_MPU_TASK_REGIONS != 12U) && (STK_MPU_TASK_REGIONS != 16U)
172 #error "STK_MPU_TASK_REGIONS_S must be defined as 2, 4, 6, 8, 12, or 16"
173#endif
174#if STK_MPU_STACK_GUARD && \
175 (STK_MPU_TASK_REGIONS_NS != 2U) && (STK_MPU_TASK_REGIONS_NS != 4U) && \
176 (STK_MPU_TASK_REGIONS_NS != 6U) && (STK_MPU_TASK_REGIONS_NS != 8U) && \
177 (STK_MPU_TASK_REGIONS_NS != 12U) && (STK_MPU_TASK_REGIONS_NS != 16U)
178 #error "STK_MPU_TASK_REGIONS_NS must be defined as 2, 4, 6, 8, 12, or 16"
179#endif
180
184#ifndef STK_TZ_SECURE
185 #if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)
186 #define STK_TZ_SECURE (1)
187 #else
188 #define STK_TZ_SECURE (0)
189 #endif
190#endif
191
195#ifndef STK_TZ_NON_SECURE
196 #if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 1)
197 #define STK_TZ_NON_SECURE (1)
198 #else
199 #define STK_TZ_NON_SECURE (0)
200 #endif
201#endif
202
203// ARM TrustZone Non-Secure binary configuration validation.
204#ifdef _STK_CORTEX_M_TRUSTZONE_NON_SECURE
205#if !STK_TZ_NON_SECURE
206 #error "Do not use -cmse compiler flag for Non-Secure binary compilation!"
207#endif
208#endif
209
210// Task MPU is supported only when MPU is enabled globally.
211#if STK_MPU_STACK_GUARD && !STK_MPU
212 #error "Enable MPU support (STK_MPU=1) to use per-task MPU feature (STK_MPU_STACK_GUARD=1)!"
213#endif
214
218#ifndef STK_CORE_FREQ_UNIFIED
219 #define STK_CORE_FREQ_UNIFIED (1U)
220#endif
221
231#if STK_SEGGER_SYSVIEW || STK_MPU_STACK_GUARD
232 #ifndef STK_STACK_NEEDS_TASK_ID
233 #define STK_STACK_NEEDS_TASK_ID (1U)
234 #endif
235#endif
236
244#if !defined(STK_SYNC_DEBUG_NAMES) && STK_SEGGER_SYSVIEW
245 #define STK_SYNC_DEBUG_NAMES (1U)
246#elif !defined(STK_SYNC_DEBUG_NAMES)
247 #define STK_SYNC_DEBUG_NAMES (0U)
248#endif
249
253#ifndef STK_STACK_GUARD
254 #define STK_STACK_GUARD (1U)
255#endif
256
260#if !STK_STRICT_COMPLIANCY
261 #define STK_VIRT_DTOR
262#else
263 #define STK_VIRT_DTOR virtual
264#endif
265
272#if defined(__GNUC__) || defined(__ICCARM__)
273 #define __stk_forceinline __attribute__((always_inline)) inline
274#elif defined(_MSC_VER)
275 #define __stk_forceinline __forceinline
276#else
277 #define __stk_forceinline inline
278#endif
279
286#if defined(__GNUC__) || defined(__ICCARM__)
287 #define __stk_aligned(x) __attribute__((aligned(x)))
288#else
289 #define __stk_aligned(x)
290#endif
291
297#if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) || defined(__CC_ARM) || defined(__ARMCC_VERSION)
298 #define __stk_weak __attribute__((weak))
299#else
300 #define __stk_weak
301#endif
302
310#if defined(__GNUC__) || defined(__ICCARM__)
311 #define __stk_attr_naked __attribute__((naked))
312#else
313 #define __stk_attr_naked
314#endif
315
321#if defined(__GNUC__) || defined(__ICCARM__)
322 #define __stk_attr_noreturn __attribute__((__noreturn__))
323#else
324 #define __stk_attr_noreturn
325#endif
326
332#if defined(__GNUC__) || defined(__ICCARM__)
333 #define __stk_attr_unused __attribute__((unused))
334#else
335 #define __stk_attr_unused
336#endif
337
343#if defined(__GNUC__) || defined(__ICCARM__)
344 #define __stk_attr_used __attribute__((used))
345#else
346 #define __stk_attr_used
347#endif
348
354#if defined(__GNUC__) || defined(__ICCARM__)
355 #define __stk_attr_noinline __attribute__((noinline))
356#else
357 #define __stk_attr_noinline
358#endif
359
365#if defined(__GNUC__) || defined(__ICCARM__)
366 #define __stk_attr_deprecated __attribute__((deprecated))
367#elif defined(_MSC_VER)
368 #define __stk_attr_deprecated __declspec(deprecated)
369#else
370 #define __stk_attr_deprecated
371#endif
372
378#if defined(__GNUC__) || defined(__clang__)
379 static __stk_forceinline void __stk_full_memfence() { __sync_synchronize(); }
380#elif defined(__ICCARM__)
381 static __stk_forceinline void __stk_full_memfence() { __DMB(); }
382#elif defined(_MSC_VER)
383 static __stk_forceinline void __stk_full_memfence() { __stk_dmb(); }
384#else
385 #error "__stk_full_memfence() is not implemented for this compiler. Add a definition to stk_defs.h."
386#endif
387
396#if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
397 static __stk_forceinline void __stk_compiler_barrier() { __asm volatile("" ::: "memory"); }
398#elif defined(_MSC_VER)
399 static __stk_forceinline void __stk_compiler_barrier() { _ReadWriteBarrier(); }
400#else
401 #error "__stk_compiler_barrier() is not implemented for this compiler. Add a definition to stk_defs.h."
402#endif
403
419#ifndef __stk_relax_cpu
420#if defined(__GNUC__) || defined(__clang__)
421 #if defined(__i386__) || defined(__x86_64__)
422 static __stk_forceinline void __stk_relax_cpu() { __builtin_ia32_pause(); }
423 #elif defined(__riscv)
424 #ifdef __riscv_zihintpause
425 static __stk_forceinline void __stk_relax_cpu() { __builtin_riscv_pause(); }
426 #else
427 static __stk_forceinline void __stk_relax_cpu() { __asm volatile("nop" ::: "memory"); }
428 #endif
429 #elif defined(__ARM_ARCH) || defined(_STK_ARCH_ARM_CORTEX_M)
430 static __stk_forceinline void __stk_relax_cpu() { __asm volatile("yield" ::: "memory"); }
431 #else
432 static __stk_forceinline void __stk_relax_cpu() { __asm volatile("" ::: "memory"); }
433 #endif
434#elif defined(__ICCARM__)
435 static __stk_forceinline void __stk_relax_cpu() { __asm volatile("YIELD"); }
436#elif defined(_MSC_VER)
437 #include <intrin.h>
438 #if defined(_M_IX86) || defined(_M_X64)
439 static __stk_forceinline void __stk_relax_cpu() { _mm_pause(); }
440 #elif defined(_M_ARM) || defined(_M_ARM64)
441 static __stk_forceinline void __stk_relax_cpu() { __yield(); }
442 #else
443 static __stk_forceinline void __stk_relax_cpu() { __stk_full_memfence(); }
444 #endif
445#else
446 #error "__stk_relax_cpu() is not implemented for this compiler. Add a definition to stk_defs.h."
447#endif
448#endif
449
464#if defined(DEBUG) || defined(_DEBUG)
465 #if defined(_STK_ARCH_ARM_CORTEX_M)
466 static __stk_forceinline void __stk_debug_break() { __asm volatile("bkpt 0"); }
467 #elif defined(_STK_ARCH_RISC_V)
468 static __stk_forceinline void __stk_debug_break() { __asm volatile("ebreak"); }
469 #elif defined(_STK_ARCH_X86_WIN32)
470 #ifdef _MSC_VER
471 static __stk_forceinline void __stk_debug_break() { __debugbreak(); }
472 #else
473 static __stk_forceinline void __stk_debug_break() { __asm volatile("int $3"); }
474 #endif
475 #else
476 static __stk_forceinline void __stk_debug_break() {}
477 #endif
478#else
480#endif
481
486#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
487 #define __stk_constexpr_cpp17 constexpr
488#else
489 #define __stk_constexpr_cpp17
490#endif
491
508#ifdef _STK_ASSERT_REDIRECT
509 extern void STK_ASSERT_HANDLER(const char *, const char *, int32_t);
510 #define STK_ASSERT(e) ((e) ? (void)0 : STK_ASSERT_HANDLER(#e, __FILE__, __LINE__))
511#else
512 #if defined(DEBUG) || defined(_DEBUG)
513 #include <cassert>
514 #define STK_ASSERT(e) assert(e)
515 #else
516 #define STK_ASSERT(e)
517 #endif
518#endif
519
528#define STK_STATIC_ASSERT_DESC_N(NAME, X, DESC) static_assert((X), DESC)
529
536#define STK_STATIC_ASSERT_DESC(X, DESC) STK_STATIC_ASSERT_DESC_N(_, X, DESC)
537
545#define STK_STATIC_ASSERT_N(NAME, X) STK_STATIC_ASSERT_DESC_N(N, (X), #X)
546
553#define STK_STATIC_ASSERT(X) STK_STATIC_ASSERT_DESC_N(_, (X), #X)
554
562#ifndef STK_STACK_MEMORY_FILLER
563 #define STK_STACK_MEMORY_FILLER (static_cast<stk::Word>((sizeof(stk::Word) <= 4U) ? 0xDEADBEEFU : 0xDEADBEEFDEADBEEFULL))
564#endif
565
569#ifndef STK_STACK_MEMORY_ALIGN
570 #if defined(__riscv)
571 #define STK_STACK_MEMORY_ALIGN (16U)
572 #elif defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
573 #define STK_STACK_MEMORY_ALIGN (8U)
574 #else // ARM, others
575 #define STK_STACK_MEMORY_ALIGN (4U)
576 #endif
577#endif
578
589#ifndef STK_CS_NESTINGS_MAX
590 #define STK_CS_NESTINGS_MAX (16U)
591#endif
592
599#ifndef STK_ARCH_CPU_COUNT
600 #define STK_ARCH_CPU_COUNT (1U)
601#endif
602
618#ifndef STK_STACK_SIZE_MIN
619 #ifdef __riscv
620 #if defined(__riscv_32e) && (__riscv_32e == 1)
621 // RISC-V RV32E (Embedded): Small 16-register file.
622 #if !defined(__riscv_flen) || (__riscv_flen == 0)
623 #define STK_STACK_SIZE_MIN (32U)
624 #else
625 // FPU present: Requires additional space for 32 FP registers.
626 #define STK_STACK_SIZE_MIN (32U + (__riscv_flen * 2))
627 #endif
628 #else
629 // Standard RISC-V (RV32I/RV64I): Large 32-register file.
630 // Higher minimum to prevent memory corruption on platforms like RP2350.
631 #if !defined(__riscv_flen) || (__riscv_flen == 0)
632 #define STK_STACK_SIZE_MIN (256U)
633 #else
634 // Standard RISC-V with FPU: Maximum frame allocation.
635 #define STK_STACK_SIZE_MIN (512U + (__riscv_flen * 2))
636 #endif
637 #endif
638 #else
639 // ARM Cortex-M and other architectures
640 #define STK_STACK_SIZE_MIN (32U)
641 #endif
642#endif
643
652#ifndef STK_SLEEP_TRAP_STACK_SIZE
653 #define STK_SLEEP_TRAP_STACK_SIZE (STK_STACK_SIZE_MIN)
654#endif
655
667template <size_t MODE, size_t FLAG, size_t ONTRUE, size_t ONFALSE>
669{
670#if defined(_MSC_VER) || defined(__ICCARM__)
671 // MSVC and IAR builds may over-allocate when the flag is not set to avoid compile errors.
672 static constexpr size_t Value = ((ONTRUE > ONFALSE) ? ONTRUE : ONFALSE);
673#else
674 // GCC and Clang support zero-sized array extensions natively.
675 static constexpr size_t Value = (((MODE & FLAG) != 0U) ? ONTRUE : ONFALSE);
676#endif
677};
678
689#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
690 #define STK_ENDIAN_IDX_HI (0U) // big-endian: high word at index 0
691 #define STK_ENDIAN_IDX_LO (1U) // big-endian: low word at index 1
692#else
693 #define STK_ENDIAN_IDX_HI (1U) // little-endian (default): high word at index 1
694 #define STK_ENDIAN_IDX_LO (0U) // little-endian (default): low word at index 0
695#endif
696
708#define STK_NONCOPYABLE_CLASS(TYPE)\
709 TYPE(const TYPE &) = delete;\
710 TYPE &operator=(const TYPE &) = delete;
711
715#define STK_UNUSED(X) static_cast<void>((X))
716
726#if __cplusplus >= 202002L
727 #define STK_LIKELY(x) ([&]() { if (!!(x)) [[likely]] { return true; } else { return false; } }())
728 #define STK_UNLIKELY(x) ([&]() { if (!!(x)) { return true; } else [[unlikely]] { return false; } }())
729#elif defined(__GNUC__) || defined(__clang__)
730 #define STK_LIKELY(x) __builtin_expect(!!(x), 1)
731 #define STK_UNLIKELY(x) __builtin_expect(!!(x), 0)
732#else
733 #define STK_LIKELY(x) (x)
734 #define STK_UNLIKELY(x) (x)
735#endif
736
742#define STK_STATIC_ARRAY_SIZE(ARRAY) static_cast<size_t>(sizeof(ARRAY) / sizeof(ARRAY[0]))
743
747namespace stk {
748
752template <typename T>
753static constexpr T Min(T a, T b) noexcept { return ((a < b) ? a : b); }
754
758template <typename T>
759static constexpr T Max(T a, T b) noexcept { return ((a > b) ? a : b); }
760
764template <typename T>
765static constexpr T Align(T v, T align) noexcept
766{
767 return ((v + align - static_cast<T>(1U)) / align) * align;
768}
769
773template <typename T>
774static constexpr T AlignPow2(T v, T align) noexcept
775{
776 return (v + align - static_cast<T>(1U)) & ~(align - static_cast<T>(1U));
777}
778
783static __stk_forceinline uint32_t CountLeadingZeros(const uint32_t value) noexcept
784{
785 uint32_t ret_val;
786 uint32_t temp_val = value;
787
788#if defined(__GNUC__) || defined(__clang__)
789 ret_val = static_cast<uint32_t>(__builtin_clz(temp_val));
790#elif defined(__ICCARM__)
791 ret_val = static_cast<uint32_t>(__CLZ(temp_val));
792#else
793 uint32_t count = 0U;
794
795 // note: binary search requires temp_val > 0 to resolve to a max of 31 leading zeros safely
796 if (temp_val <= 0x0000FFFFU) { count += 16U; temp_val = temp_val << 16U; } else { }
797 if (temp_val <= 0x00FFFFFFU) { count += 8U; temp_val = temp_val << 8U; } else { }
798 if (temp_val <= 0x0FFFFFFFU) { count += 4U; temp_val = temp_val << 4U; } else { }
799 if (temp_val <= 0x3FFFFFFFU) { count += 2U; temp_val = temp_val << 2U; } else { }
800 if (temp_val <= 0x7FFFFFFFU) { count += 1U; } else { }
801
802 ret_val = count;
803#endif
804
805 return ret_val;
806}
807
812namespace util {}
813
814} // namespace stk
815
819#ifndef _STK_CUSTOM_MEMCPY
820static void STK_MEMCPY(void *const dest, const void *const src, const size_t size);
821#endif
822
826#ifndef _STK_CUSTOM_MEMSET
827static void STK_MEMSET(void *const dest, const uint8_t value, const size_t size);
828#endif
829
830#endif /* STK_DEFS_H_ */
static void __stk_dmb()
Hardware memory barrier: ensures visibility across cores and bus masters.
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:277
static void STK_MEMCPY(void *const dest, const void *const src, const size_t size)
A wrapper for a built-in memcpy, redefine to your own if required.
static void STK_MEMSET(void *const dest, const uint8_t value, const size_t size)
A wrapper for a built-in memset, redefine to your own if required.
static void __stk_debug_break()
Definition stk_defs.h:479
Namespace of STK package.
static uint32_t CountLeadingZeros(const uint32_t value) noexcept
Count leading zeros.
Definition stk_defs.h:783
static constexpr T AlignPow2(T v, T align) noexcept
Fast compile-time alignment for power-of-two boundaries.
Definition stk_defs.h:774
static constexpr T Align(T v, T align) noexcept
Aligns a value towards the next larger size multiple.
Definition stk_defs.h:765
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:759
static constexpr T Min(T a, T b) noexcept
Compile-time minimum of two values.
Definition stk_defs.h:753
Internal utility namespace containing data structure helpers (linked lists, etc.) used by the kernel ...
Selects a static array element count at compile time based on a mode flag.
Definition stk_defs.h:669
static constexpr size_t Value
Definition stk_defs.h:675