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_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
73// Raw storage for one stk_blockpool_t, sized and aligned for the type.
78
79static struct BlockPoolSlot
80{
82 {}
83
84 stk_blockpool_t *pool() { return reinterpret_cast<stk_blockpool_t *>(reinterpret_cast<void *>(mem.data)); }
85 const stk_blockpool_t *pool() const { return reinterpret_cast<const stk_blockpool_t *>(reinterpret_cast<const void *>(mem.data)); }
86
88 bool busy;
89}
91
92// -----------------------------------------------------------------------------
93// Internal helpers
94// -----------------------------------------------------------------------------
95
96// Find the slot that owns 'pool'; returns nullptr if not found.
98{
99 BlockPoolSlot *result = nullptr;
100
101 for (size_t i = 0U; i < STK_C_BLOCKPOOL_MAX; ++i)
102 {
103 if (s_BlockPools[i].busy)
104 {
105 if (s_BlockPools[i].pool() == pool)
106 {
107 result = &s_BlockPools[i];
108 break;
109 }
110 }
111 }
112
113 return result;
114}
115
116// Acquire a free slot; returns nullptr when the pool is exhausted.
118{
119 BlockPoolSlot *result = nullptr;
120
121 for (size_t i = 0U; i < STK_C_BLOCKPOOL_MAX; ++i)
122 {
123 if (!s_BlockPools[i].busy)
124 {
125 s_BlockPools[i].busy = true;
126 result = &s_BlockPools[i];
127 break;
128 }
129 }
130
131 return result;
132}
133
134// =============================================================================
135// C-interface
136// =============================================================================
137extern "C" {
138
139// -----------------------------------------------------------------------------
140// Lifecycle — heap storage
141// -----------------------------------------------------------------------------
142
143stk_blockpool_t *stk_blockpool_create(size_t capacity, size_t raw_block_size, const char *name)
144{
145 STK_ASSERT(capacity > 0U);
146 STK_ASSERT(raw_block_size > 0U);
147
149
150 BlockPoolSlot *const slot = AcquireSlot();
151
152 // pool exhausted — increase STK_C_BLOCKPOOL_MAX
153 STK_ASSERT(slot != nullptr);
154
155 stk_blockpool_t *result = nullptr;
156 if (slot != nullptr)
157 {
158 result = ConstructIn<stk_blockpool_t>(slot->mem, capacity, raw_block_size, name);
159 }
160
161 return result;
162}
163
165 size_t raw_block_size,
166 uint8_t *storage_ptr,
167 size_t storage_size,
168 const char *name)
169{
170 STK_ASSERT(capacity > 0U);
171 STK_ASSERT(raw_block_size > 0U);
172 STK_ASSERT(storage_ptr != nullptr);
173 STK_ASSERT(storage_size >= (capacity * BlockMemoryPool::AlignBlockSize(raw_block_size)));
174
176
177 BlockPoolSlot *const slot = AcquireSlot();
178
179 // pool exhausted — increase STK_C_BLOCKPOOL_MAX
180 STK_ASSERT(slot != nullptr);
181
182 stk_blockpool_t *result = nullptr;
183 if (slot != nullptr)
184 {
185 result = ConstructIn<stk_blockpool_t>(slot->mem, capacity, raw_block_size,
186 storage_ptr, storage_size, name);
187 }
188
189 return result;
190}
191
193{
194 STK_ASSERT(pool != nullptr);
195
197
198 BlockPoolSlot *const slot = FindSlot(pool);
199
200 // pool not found: double-destroy or corruption
201 STK_ASSERT(slot != nullptr);
202 if (slot != nullptr)
203 {
204 // Explicitly run the destructor (frees heap storage if owned).
205 pool->~stk_blockpool_t();
206 slot->busy = false;
207 }
208}
209
210// -----------------------------------------------------------------------------
211// Allocation
212// -----------------------------------------------------------------------------
213
215{
216 STK_ASSERT(pool != nullptr);
217 // stk_blockpool_alloc() blocks indefinitely and must never be called from an ISR.
218 // Use stk_blockpool_try_alloc() or stk_blockpool_timed_alloc(..., STK_NO_WAIT) instead.
220
221 return pool->handle.Alloc();
222}
223
225{
226 STK_ASSERT(pool != nullptr);
227
228 return pool->handle.TimedAlloc(timeout);
229}
230
232{
233 STK_ASSERT(pool != nullptr);
234
235 return pool->handle.TryAlloc();
236}
237
238// -----------------------------------------------------------------------------
239// Deallocation
240// -----------------------------------------------------------------------------
241
243{
244 STK_ASSERT(pool != nullptr);
245
246 return pool->handle.Free(ptr);
247}
248
249// -----------------------------------------------------------------------------
250// Query
251// -----------------------------------------------------------------------------
252
254{
255 STK_ASSERT(pool != nullptr);
256
257 return pool->handle.IsStorageValid();
258}
259
261{
262 STK_ASSERT(pool != nullptr);
263
264 return pool->handle.GetCapacity();
265}
266
268{
269 STK_ASSERT(pool != nullptr);
270
271 return pool->handle.GetBlockSize();
272}
273
275{
276 STK_ASSERT(pool != nullptr);
277
278 return pool->handle.GetUsedCount();
279}
280
282{
283 STK_ASSERT(pool != nullptr);
284
285 return pool->handle.GetFreeCount();
286}
287
289{
290 STK_ASSERT(pool != nullptr);
291
292 return pool->handle.IsFull();
293}
294
296{
297 STK_ASSERT(pool != nullptr);
298
299 return pool->handle.IsEmpty();
300}
301
303{
304 STK_ASSERT(pool != nullptr);
305
306 return &pool->handle;
307}
308
309// =============================================================================
310} // extern "C"
311// =============================================================================
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:516
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:118
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.
void * stk_blockpool_alloc(stk_blockpool_t *pool)
Allocate one block, blocking indefinitely until one is available.
stk::memory::BlockMemoryPool * stk_blockpool_get_instance(stk_blockpool_t *pool)
Get the underlying C++ stk::memory::BlockMemoryPool object wrapped by a stk_blockpool_t handle.
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:144
static T * ConstructIn(Mem &mem, Args &&... args)
Construct object T in-place inside a C memory container.
Definition stk_c.h:2198
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Memory-related primitives.
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 data[StkGetWordCountForType< stk_blockpool_t >()]
BlockPoolMem mem
stk_blockpool_t * pool()
const stk_blockpool_t * pool() const