SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_c_memory.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#include <cstddef> // for std::size_t
11
12#include <stk_config.h>
13#include <stk.h>
14#include <memory/stk_memory.h>
15
16#include "stk_c.h"
17#include "stk_c_memory.h"
18
19using namespace stk;
20using namespace stk::memory;
21
22// Guard against divergence between the C macro STK_BLOCKPOOL_ALIGN_BLOCK_SIZE and
23// the C++ BlockMemoryPool::AlignBlockSize() function. Both must produce identical
24// results; if this assertion fires, update one of the two definitions.
25static_assert(
31 "STK_BLOCKPOOL_ALIGN_BLOCK_SIZE and BlockMemoryPool::AlignBlockSize() have diverged. "
32 "Keep both definitions in sync.");
33
34// Returns a size of memory in stk::Word elements required for object allocation.
35template <typename T> static constexpr size_t StkGetWordCountForType()
36{
37 return ((sizeof(T) + sizeof(stk::Word) - 1U) / sizeof(stk::Word));
38}
39
40// Private memory allocators (we define malloc, free here to overcome absence of declaration in
41// case of -ffreestanding compiler flag).
42extern "C" void *malloc(size_t size);
43extern "C" void free(void *ptr);
44void *stk::memory::MemoryAllocator::Allocate(size_t size) { return malloc(size); }
46
47// -----------------------------------------------------------------------------
48// stk_blockpool_t — wraps a BlockMemoryPool instance
49//
50// The struct is opaque to C callers. Instances live in s_BlockPools[].
51// -----------------------------------------------------------------------------
52
54{
55 // Constructor forwarded to the external-storage BlockMemoryPool ctor.
56 stk_blockpool_t(size_t capacity, size_t raw_block_size,
57 uint8_t *storage, size_t storage_size, const char *name)
58 : handle(capacity, raw_block_size, storage, storage_size, name)
59 {}
60
61 // Constructor forwarded to the heap-storage BlockMemoryPool ctor.
62 stk_blockpool_t(size_t capacity, size_t raw_block_size, const char *name)
63 : handle(capacity, raw_block_size, name)
64 {}
65
67};
68
69// -----------------------------------------------------------------------------
70// Static pool of stk_blockpool_t slots
71// -----------------------------------------------------------------------------
72
73static struct BlockPoolSlot
74{
76 {}
77
78 stk_blockpool_t *pool() { return reinterpret_cast<stk_blockpool_t *>(reinterpret_cast<void *>(storage)); }
79 const stk_blockpool_t *pool() const { return reinterpret_cast<const stk_blockpool_t *>(reinterpret_cast<const void *>(storage)); }
80
82 bool busy;
83}
85
86// -----------------------------------------------------------------------------
87// Internal helpers
88// -----------------------------------------------------------------------------
89
90// Find the slot that owns 'pool'; returns nullptr if not found.
92{
93 BlockPoolSlot *result = nullptr;
94
95 for (size_t i = 0U; i < STK_C_BLOCKPOOL_MAX; ++i)
96 {
97 if (s_BlockPools[i].busy)
98 {
99 if (s_BlockPools[i].pool() == pool)
100 {
101 result = &s_BlockPools[i];
102 break;
103 }
104 }
105 }
106
107 return result;
108}
109
110// Acquire a free slot; returns nullptr when the pool is exhausted.
112{
113 BlockPoolSlot *result = nullptr;
114
115 for (size_t i = 0U; i < STK_C_BLOCKPOOL_MAX; ++i)
116 {
117 if (!s_BlockPools[i].busy)
118 {
119 s_BlockPools[i].busy = true;
120 result = &s_BlockPools[i];
121 break;
122 }
123 }
124
125 return result;
126}
127
128// =============================================================================
129// C-interface
130// =============================================================================
131extern "C" {
132
133// -----------------------------------------------------------------------------
134// Lifecycle — heap storage
135// -----------------------------------------------------------------------------
136
137stk_blockpool_t *stk_blockpool_create(size_t capacity, size_t raw_block_size, const char *name)
138{
139 STK_ASSERT(capacity > 0U);
140 STK_ASSERT(raw_block_size > 0U);
141
143
144 BlockPoolSlot *const slot = AcquireSlot();
145
146 // pool exhausted — increase STK_C_BLOCKPOOL_MAX
147 STK_ASSERT(slot != nullptr);
148
149 stk_blockpool_t *result = nullptr;
150 if (slot != nullptr)
151 {
152 result = new (slot->storage) stk_blockpool_t(capacity, raw_block_size, name);
153 }
154
155 return result;
156}
157
159 size_t raw_block_size,
160 uint8_t *storage_ptr,
161 size_t storage_size,
162 const char *name)
163{
164 STK_ASSERT(capacity > 0U);
165 STK_ASSERT(raw_block_size > 0U);
166 STK_ASSERT(storage_ptr != nullptr);
167 STK_ASSERT(storage_size >= (capacity * BlockMemoryPool::AlignBlockSize(raw_block_size)));
168
170
171 BlockPoolSlot *const slot = AcquireSlot();
172
173 // pool exhausted — increase STK_C_BLOCKPOOL_MAX
174 STK_ASSERT(slot != nullptr);
175
176 stk_blockpool_t *result = nullptr;
177 if (slot != nullptr)
178 {
179 result = new (slot->storage) stk_blockpool_t(capacity, raw_block_size,
180 storage_ptr, storage_size, name);
181 }
182
183 return result;
184}
185
187{
188 STK_ASSERT(pool != nullptr);
189
191
192 BlockPoolSlot *const slot = FindSlot(pool);
193
194 // pool not found: double-destroy or corruption
195 STK_ASSERT(slot != nullptr);
196 if (slot != nullptr)
197 {
198 // Explicitly run the destructor (frees heap storage if owned).
199 pool->~stk_blockpool_t();
200 slot->busy = false;
201 }
202}
203
204// -----------------------------------------------------------------------------
205// Allocation
206// -----------------------------------------------------------------------------
207
209{
210 STK_ASSERT(pool != nullptr);
211 // stk_blockpool_alloc() blocks indefinitely and must never be called from an ISR.
212 // Use stk_blockpool_try_alloc() or stk_blockpool_timed_alloc(..., STK_NO_WAIT) instead.
214
215 return pool->handle.Alloc();
216}
217
219{
220 STK_ASSERT(pool != nullptr);
221
222 return pool->handle.TimedAlloc(timeout);
223}
224
226{
227 STK_ASSERT(pool != nullptr);
228
229 return pool->handle.TryAlloc();
230}
231
232// -----------------------------------------------------------------------------
233// Deallocation
234// -----------------------------------------------------------------------------
235
237{
238 STK_ASSERT(pool != nullptr);
239
240 return pool->handle.Free(ptr);
241}
242
243// -----------------------------------------------------------------------------
244// Query
245// -----------------------------------------------------------------------------
246
248{
249 STK_ASSERT(pool != nullptr);
250
251 return pool->handle.IsStorageValid();
252}
253
255{
256 STK_ASSERT(pool != nullptr);
257
258 return pool->handle.GetCapacity();
259}
260
262{
263 STK_ASSERT(pool != nullptr);
264
265 return pool->handle.GetBlockSize();
266}
267
269{
270 STK_ASSERT(pool != nullptr);
271
272 return pool->handle.GetUsedCount();
273}
274
276{
277 STK_ASSERT(pool != nullptr);
278
279 return pool->handle.GetFreeCount();
280}
281
283{
284 STK_ASSERT(pool != nullptr);
285
286 return pool->handle.IsFull();
287}
288
290{
291 STK_ASSERT(pool != nullptr);
292
293 return pool->handle.IsEmpty();
294}
295
296// =============================================================================
297} // extern "C"
298// =============================================================================
Collection of memory-related primitives (stk::memory namespace).
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
C language binding/interface for SuperTinyKernel RTOS.
C language binding for stk::memory::BlockMemoryPool.
static BlockPoolSlot * FindSlot(const stk_blockpool_t *pool)
static constexpr size_t StkGetWordCountForType()
void * malloc(size_t size)
static BlockPoolSlot * AcquireSlot()
static struct BlockPoolSlot s_BlockPools[(8U)]
void free(void *ptr)
int32_t stk_timeout_t
Timeout value.
Definition stk_c.h:113
size_t stk_blockpool_get_capacity(const stk_blockpool_t *pool)
Get the total block capacity of the pool.
void * stk_blockpool_timed_alloc(stk_blockpool_t *pool, stk_timeout_t timeout)
Allocate one block, blocking until one becomes available or the timeout expires.
void stk_blockpool_destroy(stk_blockpool_t *pool)
Destroy a pool and return its slot to the static pool.
bool stk_blockpool_is_storage_valid(const stk_blockpool_t *pool)
Verify that the backing storage is valid and the pool is ready for use.
#define STK_C_BLOCKPOOL_MAX
Maximum number of concurrent stk_blockpool_t instances (default: 8).
size_t stk_blockpool_get_used_count(const stk_blockpool_t *pool)
Get the number of currently allocated (outstanding) blocks.
struct stk_blockpool_t stk_blockpool_t
Opaque handle to a stk::memory::BlockMemoryPool instance.
void * stk_blockpool_alloc(stk_blockpool_t *pool)
Allocate one block, blocking indefinitely until one is available.
bool stk_blockpool_free(stk_blockpool_t *pool, void *ptr)
Return a previously allocated block to the pool.
void * stk_blockpool_try_alloc(stk_blockpool_t *pool)
Non-blocking allocation attempt.
stk_blockpool_t * stk_blockpool_create_static(size_t capacity, size_t raw_block_size, uint8_t *storage, size_t storage_size, const char *name)
Create a block pool backed by caller-supplied (external) storage.
stk_blockpool_t * stk_blockpool_create(size_t capacity, size_t raw_block_size, const char *name)
Create a block pool backed by heap-allocated storage.
bool stk_blockpool_is_empty(const stk_blockpool_t *pool)
Check whether all blocks are free (no outstanding allocations).
bool stk_blockpool_is_full(const stk_blockpool_t *pool)
Check whether all blocks are currently allocated (pool exhausted).
size_t stk_blockpool_get_free_count(const stk_blockpool_t *pool)
Get the number of free (available) blocks.
size_t stk_blockpool_get_block_size(const stk_blockpool_t *pool)
Get the aligned block size used internally by the allocator.
#define STK_BLOCKPOOL_ALIGN_BLOCK_SIZE(raw_size)
Compute the internally aligned block size for a given raw byte size.
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:115
Memory-related primitives.
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
static void Free(void *ptr) __stk_weak
Free the memory chunk.
static void * Allocate(size_t size) __stk_weak
Allocate the memory chunk.
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics.
size_t GetUsedCount() const
Get the number of currently allocated (outstanding) blocks.
size_t GetFreeCount() const
Get the number of free (available) blocks.
size_t GetCapacity() const
Get the total block capacity of the pool.
bool IsFull() const
Check whether all blocks are currently allocated (pool exhausted).
bool IsStorageValid() const
Verify that the backing storage is valid and the pool is ready for use.
bool Free(void *ptr)
Return a previously allocated block to the pool.
void * TryAlloc()
Non-blocking allocation attempt.
static constexpr size_t AlignBlockSize(size_t raw_size)
Round a raw block size up to the nearest multiple of BLOCK_ALIGN.
void * TimedAlloc(Timeout timeout_ticks=WAIT_INFINITE)
Allocate one block, blocking until one becomes available or the timeout expires.
size_t GetBlockSize() const
Get the aligned block size used internally by the allocator.
void * Alloc()
Allocate one block, blocking indefinitely until one is available.
bool IsEmpty() const
Check whether all blocks are free (no outstanding allocations).
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
stk_blockpool_t(size_t capacity, size_t raw_block_size, uint8_t *storage, size_t storage_size, const char *name)
stk_blockpool_t(size_t capacity, size_t raw_block_size, const char *name)
BlockMemoryPool handle
Word storage[StkGetWordCountForType< stk_blockpool_t >()]
stk_blockpool_t * pool()
const stk_blockpool_t * pool() const