![]() |
SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
|
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics. More...
#include <stk_memory_blockpool.h>
Classes | |
| struct | MemoryBlock |
| Intrusive free-list node overlaid on the first word of every free block. More... | |
Public Member Functions | |
| BlockMemoryPool (size_t capacity, size_t raw_block_size, uint8_t *storage, size_t storage_size, const char *name=nullptr) | |
| Construct a pool backed by caller-supplied (external) storage. | |
| BlockMemoryPool (size_t capacity, size_t raw_block_size, const char *name=nullptr) | |
| Construct a pool with heap-allocated storage. | |
| STK_VIRT_DTOR | ~BlockMemoryPool () |
| Destructor. | |
| void * | TimedAlloc (Timeout timeout_ticks=WAIT_INFINITE) |
| Allocate one block, blocking until one becomes available or the timeout expires. | |
| template<typename T> | |
| T * | TimedAllocT (Timeout timeout_ticks=WAIT_INFINITE) |
| Allocate one typed block, blocking until one becomes available or the timeout expires. | |
| void * | Alloc () |
| Allocate one block, blocking indefinitely until one is available. | |
| template<typename T> | |
| T * | AllocT () |
| Allocate one typed block, blocking indefinitely until one is available. | |
| void * | TryAlloc () |
| Non-blocking allocation attempt. | |
| template<typename T> | |
| T * | TryAllocT () |
| Non-blocking typed allocation attempt. | |
| bool | Free (void *ptr) |
| Return a previously allocated block to the pool. | |
| bool | IsStorageValid () const |
| Verify that the backing storage is valid and the pool is ready for use. | |
| size_t | GetCapacity () const |
| Get the total block capacity of the pool. | |
| size_t | GetBlockSize () const |
| Get the aligned block size used internally by the allocator. | |
| size_t | GetUsedCount () const |
| Get the number of currently allocated (outstanding) blocks. | |
| size_t | GetFreeCount () const |
| Get the number of free (available) blocks. | |
| bool | IsFull () const |
| Check whether all blocks are currently allocated (pool exhausted). | |
| bool | IsEmpty () const |
| Check whether all blocks are free (no outstanding allocations). | |
| void | SetTraceName (const char *name) |
| Set name. | |
| const char * | GetTraceName () const |
| Get name. | |
Static Public Member Functions | |
| static constexpr size_t | AlignBlockSize (size_t raw_size) |
Round a raw block size up to the nearest multiple of BLOCK_ALIGN. | |
Static Public Attributes | |
| static const size_t | CAPACITY_MAX = 0xFFFEU |
| Max capacity supported (number of blocks). | |
Private Member Functions | |
| STK_NONCOPYABLE_CLASS (BlockMemoryPool) | |
| void | BuildFreeList () |
Initialise the intrusive free-list across m_storage. | |
| void * | PopFreeList () |
Pop the head block from the free-list, increment m_used_count, and return it. | |
Private Attributes | |
| uint8_t * | m_storage |
| flat byte array holding all N blocks (owned or external) | |
| MemoryBlock * | m_free_list |
| head of the intrusive free-list (nullptr when pool is empty) | |
| sync::ConditionVariable | m_cv |
| signalled by Free() to wake one task blocked in TimedAlloc() | |
| size_t | m_block_size |
| aligned block size in bytes (>= BLOCK_ALIGN) | |
| size_t | m_capacity |
| total number of blocks | |
| size_t | m_used_count |
| number of blocks currently allocated (outstanding) | |
| bool | m_storage_owned |
| true -> storage is heap-allocated; free in destructor | |
Static Private Attributes | |
| static const uint32_t | BLOCK_ALIGN = static_cast<uint32_t>(sizeof(MemoryBlock)) |
Minimum block alignment in bytes: sizeof(MemoryBlock). | |
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics.
BlockMemoryPool provides a deterministic, fragmentation-free allocator for scenarios where the same block size is repeatedly allocated and released - such as packet buffers, sensor sample records, or task-local state objects.
The pool uses an intrusive singly-linked free-list inside the storage array. When a block is free, its first sizeof(void*) bytes hold a pointer to the next free block; no separate metadata array is needed. Alloc and Free are therefore O(1) with a minimal critical section.
Memory layout (pool storage, contiguous):
[ block_0 | block_1 | ... | block_{n-1} ]
^ ^
m_storage (m_storage + n * m_block_size)
At construction all blocks are chained: block_i->next = block_{i+1},
last->next = nullptr. m_free_list points to block_0.
Two storage modes** mirror the CMSIS osMemoryPoolAttr_t mp_mem / mp_size fields and allow fully static (zero-heap) deployments:
| Mode | Constructor | Frees storage? |
|---|---|---|
| External storage | BlockMemoryPool(cap, blksz, buf, bufsz [, name]) | No - caller |
| Heap storage | BlockMemoryPool(cap, blksz [, name]) | Yes - dtor |
Blocking semantics**: TimedAlloc() suspends the calling task via a ConditionVariable until Free() returns a block, or the timeout expires. This replaces the spin-yield polling loop that was used in the old CMSIS wrapper, giving up the CPU completely while blocked instead of burning cycles.
ISR safety**: TryAlloc() and Free() are ISR-safe (guarded by a critical section). Alloc() and TimedAlloc() with a non-zero timeout must only be called from task context.
TryAlloc() and Free() are always available regardless of kernel mode. Definition at line 96 of file stk_memory_blockpool.h.
|
inlineexplicit |
Construct a pool backed by caller-supplied (external) storage.
The pool references storage directly without taking ownership. The caller must keep the buffer alive for the entire lifetime of this object. The storage is not freed on destruction.
| [in] | capacity | Total number of blocks the pool can hold. |
| [in] | raw_block_size | Requested per-block size in bytes. Rounded up internally to AlignBlockSize(raw_block_size). |
| [in] | storage | Pointer to a caller-owned byte buffer. Must be aligned to at least sizeof(void*) and sized to hold at least capacity * AlignBlockSize(raw_block_size) bytes. Asserted at construction time. |
| [in] | storage_size | Size of storage in bytes (used for the size assertion). |
| [in] | name | Optional name forwarded to ITraceable::SetTraceName(). |
mp_mem / mp_size path in osMemoryPoolNew(). Definition at line 327 of file stk_memory_blockpool.h.
References AlignBlockSize(), BuildFreeList(), CAPACITY_MAX, m_block_size, m_capacity, m_free_list, m_storage, m_storage_owned, m_used_count, stk::ITraceable::SetTraceName(), STK_ASSERT, and STK_UNUSED.
Referenced by STK_NONCOPYABLE_CLASS().
|
inlineexplicit |
Construct a pool with heap-allocated storage.
Allocates a flat byte buffer of capacity * AlignBlockSize(raw_block_size) bytes via operator new (std::nothrow). When exceptions are disabled (embedded default), check IsStorageValid() immediately after construction to detect allocation failure before first use.
| [in] | capacity | Total number of blocks. |
| [in] | raw_block_size | Requested per-block size in bytes. |
| [in] | name | Optional name forwarded to ITraceable::SetTraceName(). |
osMemoryPoolNew(). Definition at line 360 of file stk_memory_blockpool.h.
References AlignBlockSize(), BuildFreeList(), CAPACITY_MAX, m_block_size, m_capacity, m_free_list, m_storage, m_storage_owned, m_used_count, stk::ITraceable::SetTraceName(), STK_ASSERT, and STK_UNUSED.
|
inline |
Destructor.
Frees heap-allocated storage if m_storage_owned is true. External storage is never touched.
Alloc() or TimedAlloc() is a logical error (dangling waiters). An assertion is triggered in debug builds inside the ConditionVariable destructor. Definition at line 386 of file stk_memory_blockpool.h.
References stk::memory::MemoryAllocator::FreeArrayT(), m_block_size, m_capacity, m_storage, and m_storage_owned.
|
inlinestaticconstexpr |
Round a raw block size up to the nearest multiple of BLOCK_ALIGN.
Enforces a minimum of BLOCK_ALIGN so the free-list link always fits inside every free block without extra metadata.
| [in] | raw_size | Requested block size in bytes. |
BLOCK_ALIGN). Definition at line 158 of file stk_memory_blockpool.h.
References BLOCK_ALIGN, and stk::Max().
Referenced by BlockMemoryPool(), BlockMemoryPool(), MsgBufSlotCount(), osMemoryPoolNew(), stk_blockpool_create_static(), xMessageBufferCreateStatic(), xMessageBufferCreateStaticWithCallback(), and xMessageBufferCreateWithCallback().
|
inline |
Allocate one block, blocking indefinitely until one is available.
nullptr. Definition at line 444 of file stk_memory_blockpool.h.
References TimedAlloc(), and stk::WAIT_INFINITE.
Referenced by stk_blockpool_alloc().
|
inline |
Allocate one typed block, blocking indefinitely until one is available.
nullptr. Definition at line 450 of file stk_memory_blockpool.h.
References TimedAllocT(), and stk::WAIT_INFINITE.
|
inlineprivate |
Initialise the intrusive free-list across m_storage.
Links blocks in reverse order so after the loop m_free_list points to block_0 (lowest address), giving ascending allocation order. Each free block stores a pointer to the next free block in its own first sizeof(MemoryBlock) bytes - zero extra metadata.
Definition at line 540 of file stk_memory_blockpool.h.
References BLOCK_ALIGN, m_block_size, m_capacity, m_free_list, m_storage, m_used_count, stk::memory::BlockMemoryPool::MemoryBlock::next, stk::hw::PtrToWord(), STK_ASSERT, and stk::hw::WordToPtr().
Referenced by BlockMemoryPool(), and BlockMemoryPool().
|
inline |
Return a previously allocated block to the pool.
Pushes the block back onto the free-list head in O(1) and wakes exactly one task blocked inside Alloc() or TimedAlloc(), if any. The woken task is guaranteed to find a free block available.
| [in] | ptr | Pointer previously returned by Alloc(), TimedAlloc(), or TryAlloc(). Must not be nullptr and must belong to this pool instance. Bounds and alignment are validated; failures trigger an assertion in debug builds and return false in release builds. |
true - block successfully returned. false - ptr is nullptr, out of range, or misaligned; each case indicates a caller logic error. Free() to prevent this. Definition at line 470 of file stk_memory_blockpool.h.
References m_block_size, m_capacity, m_cv, m_free_list, m_storage, m_used_count, stk::memory::BlockMemoryPool::MemoryBlock::next, stk::hw::PtrToWord(), and STK_ASSERT.
Referenced by stk_blockpool_free(), xMessageBufferReceive(), xMessageBufferReceiveFromISR(), xMessageBufferReset(), xMessageBufferResetFromISR(), xMessageBufferSend(), and xMessageBufferSendFromISR().
|
inline |
Get the aligned block size used internally by the allocator.
Equal to AlignBlockSize(raw_block_size) passed at construction. Always >= BLOCK_ALIGN. Matches osMemoryPoolGetBlockSize().
Definition at line 254 of file stk_memory_blockpool.h.
References m_block_size.
Referenced by osMemoryPoolGetBlockSize(), and stk_blockpool_get_block_size().
|
inline |
Get the total block capacity of the pool.
osMemoryPoolGetCapacity(). Definition at line 246 of file stk_memory_blockpool.h.
References m_capacity.
Referenced by stk_blockpool_get_capacity().
|
inline |
Get the number of free (available) blocks.
GetCapacity() - GetUsedCount(). Matches osMemoryPoolGetSpace(). Definition at line 268 of file stk_memory_blockpool.h.
References m_capacity, and m_used_count.
Referenced by IsFull(), and stk_blockpool_get_free_count().
|
inlineinherited |
Get name.
NULL if not set or if STK_SYNC_DEBUG_NAMES is 0. Definition at line 433 of file stk_common.h.
|
inline |
Get the number of currently allocated (outstanding) blocks.
osMemoryPoolGetCount(). Definition at line 261 of file stk_memory_blockpool.h.
References m_used_count.
Referenced by stk_blockpool_get_used_count().
|
inline |
Check whether all blocks are free (no outstanding allocations).
true if no blocks are currently allocated. Definition at line 280 of file stk_memory_blockpool.h.
References m_used_count.
Referenced by stk_blockpool_is_empty().
|
inline |
Check whether all blocks are currently allocated (pool exhausted).
true if no blocks are available for allocation. Definition at line 274 of file stk_memory_blockpool.h.
References GetFreeCount().
Referenced by stk_blockpool_is_full().
|
inline |
Verify that the backing storage is valid and the pool is ready for use.
Always true for pools constructed with external storage. For heap-constructed pools, false if operator new failed. Must be checked after the heap constructor when operating without exceptions (the typical embedded configuration).
true if the pool is ready for use. Definition at line 239 of file stk_memory_blockpool.h.
References m_storage.
Referenced by osMemoryPoolNew(), stk_blockpool_is_storage_valid(), and xMessageBufferCreate().
|
inlineprivate |
Pop the head block from the free-list, increment m_used_count, and return it.
m_free_list != nullptr. Definition at line 558 of file stk_memory_blockpool.h.
References m_capacity, m_free_list, m_used_count, stk::memory::BlockMemoryPool::MemoryBlock::next, and STK_ASSERT.
Referenced by TimedAlloc().
|
inlineinherited |
Set name.
| [in] | name | Null-terminated string or NULL. |
Definition at line 421 of file stk_common.h.
References STK_UNUSED.
Referenced by stk::memory::BlockMemoryPool::BlockMemoryPool(), and stk::memory::BlockMemoryPool::BlockMemoryPool().
|
private |
|
inline |
Allocate one block, blocking until one becomes available or the timeout expires.
If the pool is empty the calling task is suspended via the internal ConditionVariable and woken by the next Free() call. On return the caller owns the block and must eventually return it via Free().
| [in] | timeout_ticks | Maximum time to wait (ticks). WAIT_INFINITE - block indefinitely (default). NO_WAIT - return nullptr immediately if pool is empty (identical to TryAlloc(); ISR-safe). |
GetRawBlockSize() bytes, or nullptr if the timeout expired before a block became available. NO_WAIT; ISR-unsafe otherwise. Definition at line 402 of file stk_memory_blockpool.h.
References stk::hw::IsInsideISR(), m_cv, m_free_list, stk::NO_WAIT, PopFreeList(), and STK_ASSERT.
Referenced by Alloc(), stk_blockpool_timed_alloc(), TimedAllocT(), TryAlloc(), xMessageBufferSend(), and xMessageBufferSendFromISR().
|
inline |
Allocate one typed block, blocking until one becomes available or the timeout expires.
Thin typed wrapper around TimedAlloc(). Asserts that sizeof(T) fits within the aligned block size chosen at construction.
| [in] | timeout_ticks | Maximum time to wait (ticks). Same semantics as TimedAlloc(). |
nullptr if the timeout expired. NO_WAIT; ISR-unsafe otherwise. Definition at line 437 of file stk_memory_blockpool.h.
References m_block_size, STK_ASSERT, and TimedAlloc().
Referenced by AllocT(), and TryAllocT().
|
inline |
Non-blocking allocation attempt.
Returns a block immediately if the pool is not empty, or nullptr if all blocks are currently allocated. Never suspends the calling task.
nullptr if the pool is empty. Definition at line 455 of file stk_memory_blockpool.h.
References stk::NO_WAIT, and TimedAlloc().
Referenced by stk_blockpool_try_alloc().
|
inline |
Non-blocking typed allocation attempt.
Returns a typed pointer immediately if the pool is not empty, or nullptr if all blocks are currently allocated. Never suspends the calling task.
nullptr if the pool is empty. Definition at line 461 of file stk_memory_blockpool.h.
References stk::NO_WAIT, and TimedAllocT().
|
staticprivate |
Minimum block alignment in bytes: sizeof(MemoryBlock).
Ensures the intrusive free-list pointer stored in the first word of every free block is naturally aligned on all supported STK targets.
Definition at line 299 of file stk_memory_blockpool.h.
Referenced by AlignBlockSize(), and BuildFreeList().
|
static |
Max capacity supported (number of blocks).
Definition at line 101 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), and BlockMemoryPool().
|
private |
aligned block size in bytes (>= BLOCK_ALIGN)
Definition at line 317 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), GetBlockSize(), TimedAllocT(), and ~BlockMemoryPool().
|
private |
total number of blocks
Definition at line 318 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), GetCapacity(), GetFreeCount(), PopFreeList(), and ~BlockMemoryPool().
|
private |
signalled by Free() to wake one task blocked in TimedAlloc()
Definition at line 316 of file stk_memory_blockpool.h.
Referenced by Free(), and TimedAlloc().
|
private |
head of the intrusive free-list (nullptr when pool is empty)
Definition at line 315 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), PopFreeList(), and TimedAlloc().
|
private |
flat byte array holding all N blocks (owned or external)
Definition at line 314 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), IsStorageValid(), and ~BlockMemoryPool().
|
private |
true -> storage is heap-allocated; free in destructor
Definition at line 320 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), and ~BlockMemoryPool().
|
private |
number of blocks currently allocated (outstanding)
Definition at line 319 of file stk_memory_blockpool.h.
Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), GetFreeCount(), GetUsedCount(), IsEmpty(), and PopFreeList().