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::memory::BlockMemoryPool Class Reference

Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics. More...

#include <stk_memory_blockpool.h>

Inheritance diagram for stk::memory::BlockMemoryPool:
Collaboration diagram for stk::memory::BlockMemoryPool:

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.
EWaitResult TimedAllocEx (void **block, Timeout timeout_ticks=WAIT_INFINITE)
 Allocate one block, preserving the full wait outcome.
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 size_t BLOCK_ALIGN = static_cast<size_t>(sizeof(MemoryBlock))
 Minimum block alignment in bytes: sizeof(MemoryBlock).

Detailed Description

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.

// -----------------------------------------------------------------------
// Example 1 - native STK usage with zero-heap external storage
// -----------------------------------------------------------------------
static const uint32_t PKT_COUNT = 8U;
static const uint32_t PKT_SIZE = sizeof(Packet);
alignas(sizeof(void *)) static uint8_t
g_PktStorage[PKT_COUNT * stk::memory::BlockMemoryPool::AlignBlockSize(PKT_SIZE)];
stk::memory::BlockMemoryPool g_PktPool(PKT_COUNT, PKT_SIZE,
g_PktStorage, sizeof(g_PktStorage));
void ISR_Receiver() {
void *blk = g_PktPool.TryAlloc(); // ISR-safe, non-blocking
if (blk) {
FillPacket(static_cast<Packet *>(blk));
g_ParseQueue.Write(blk, NO_WAIT);
}
}
void Task_Parser() {
void *blk = nullptr;
if (g_ParseQueue.Read(blk)) {
Parse(static_cast<Packet *>(blk));
g_PktPool.Free(blk); // O(1), wakes one blocked allocator
}
}
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:234
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics.
static constexpr size_t AlignBlockSize(size_t raw_size)
Round a raw block size up to the nearest multiple of BLOCK_ALIGN.
See also
sync::ConditionVariable, sync::Semaphore, sync::Pipe
Note
Blocking alloc paths require the kernel to be compiled with KERNEL_SYNC. TryAlloc() and Free() are always available regardless of kernel mode.

Definition at line 96 of file stk_memory_blockpool.h.

Constructor & Destructor Documentation

◆ BlockMemoryPool() [1/2]

stk::memory::BlockMemoryPool::BlockMemoryPool ( size_t capacity,
size_t raw_block_size,
uint8_t * storage,
size_t storage_size,
const char * name = nullptr )
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.

Parameters
[in]capacityTotal number of blocks the pool can hold.
[in]raw_block_sizeRequested per-block size in bytes. Rounded up internally to AlignBlockSize(raw_block_size).
[in]storagePointer 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_sizeSize of storage in bytes (used for the size assertion).
[in]nameOptional name forwarded to ITraceable::SetTraceName().
Note
Mirrors the mp_mem / mp_size path in osMemoryPoolNew().
ISR-unsafe (must be called from task or init context).

Definition at line 352 of file stk_memory_blockpool.h.

354: m_storage(storage),
355 m_free_list(nullptr),
356 m_block_size(AlignBlockSize(raw_block_size)),
357 m_capacity(capacity),
358 m_used_count(0U),
359 m_storage_owned(false)
360{
361 STK_ASSERT(capacity > 0U);
362 STK_ASSERT(capacity <= CAPACITY_MAX);
363 STK_ASSERT(raw_block_size > 0U);
364 STK_ASSERT(storage != nullptr);
365
366 // API contract: caller-supplied buffer must be large enough
367 STK_ASSERT(storage_size >= (capacity * m_block_size));
368
369 // in Release builds we ensure capacity which fits storage size, in Debug build the assertion above will be hit
370 if ((capacity * m_block_size) > storage_size)
371 {
372 m_capacity = storage_size / m_block_size;
373 }
374
375#if STK_SYNC_DEBUG_NAMES
376 SetTraceName(name);
377#else
378 STK_UNUSED(name);
379#endif
380
382}
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
uint8_t * m_storage
flat byte array holding all N blocks (owned or external)
static const size_t CAPACITY_MAX
Max capacity supported (number of blocks).
size_t m_capacity
total number of blocks
void BuildFreeList()
Initialise the intrusive free-list across m_storage.
MemoryBlock * m_free_list
head of the intrusive free-list (nullptr when pool is empty)
size_t m_used_count
number of blocks currently allocated (outstanding)
size_t m_block_size
aligned block size in bytes (>= BLOCK_ALIGN)
bool m_storage_owned
true -> storage is heap-allocated; free in destructor
void SetTraceName(const char *name)
Set name.
Definition stk_common.h:570

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().

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

◆ BlockMemoryPool() [2/2]

stk::memory::BlockMemoryPool::BlockMemoryPool ( size_t capacity,
size_t raw_block_size,
const char * name = nullptr )
inlineexplicit

Construct a pool with heap-allocated storage.

Allocates a flat byte buffer of capacity * AlignBlockSize(raw_block_size) bytes via MemoryAllocator::AllocateArrayT (non-throwing). When exceptions are disabled (embedded default), check IsStorageValid() immediately after construction to detect allocation failure before first use.

Parameters
[in]capacityTotal number of blocks.
[in]raw_block_sizeRequested per-block size in bytes.
[in]nameOptional name forwarded to ITraceable::SetTraceName().
Note
Mirrors the heap-fallback path in osMemoryPoolNew().
ISR-unsafe.

Definition at line 385 of file stk_memory_blockpool.h.

387 m_free_list(nullptr),
388 m_block_size(AlignBlockSize(raw_block_size)),
389 m_capacity(capacity),
390 m_used_count(0U),
391 m_storage_owned(true)
392{
393 STK_ASSERT(capacity > 0U);
394 STK_ASSERT(capacity <= CAPACITY_MAX);
395 STK_ASSERT(raw_block_size > 0U);
396
397#if STK_SYNC_DEBUG_NAMES
398 SetTraceName(name);
399#else
400 STK_UNUSED(name);
401#endif
402
403 if (m_storage != nullptr)
404 {
406 }
407 // else: m_free_list remains nullptr; caller must check IsStorageValid()
408}
static TElement * AllocateArrayT(size_t count, TArgs &&...args)
Allocate an array of elements and default/copy-construct each one.

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.

Here is the call graph for this function:

◆ ~BlockMemoryPool()

stk::memory::BlockMemoryPool::~BlockMemoryPool ( )
inline

Destructor.

Frees heap-allocated storage if m_storage_owned is true. External storage is never touched.

Note
Destroying the pool while tasks are blocked in Alloc() or TimedAlloc() is a logical error (dangling waiters). An assertion is triggered in debug builds inside the ConditionVariable destructor.
MISRA deviation: [STK-DEV-005] Rule 10-3-2.

Definition at line 411 of file stk_memory_blockpool.h.

412{
413 // ConditionVariable destructor asserts the wait list is empty
414#if STK_MEMORY_PLACEMENT_NEW
415 if (m_storage_owned)
416 {
418 m_storage = nullptr;
419 }
420#endif
421}
static void FreeArrayT(TElement ptr[], size_t count)
Destroy and free an array allocated via AllocateT().

References stk::memory::MemoryAllocator::FreeArrayT(), m_block_size, m_capacity, m_storage, and m_storage_owned.

Referenced by tx_block_pool_delete().

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

Member Function Documentation

◆ AlignBlockSize()

constexpr size_t stk::memory::BlockMemoryPool::AlignBlockSize ( size_t raw_size)
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.

Parameters
[in]raw_sizeRequested block size in bytes.
Returns
Aligned block size in bytes (>= BLOCK_ALIGN).
Note
Use this to compute the required external storage buffer size:
uint8_t buf[N * BlockMemoryPool::AlignBlockSize(sizeof(MyType))];

Definition at line 158 of file stk_memory_blockpool.h.

159 {
160 return Max(BLOCK_ALIGN, (raw_size + (BLOCK_ALIGN - 1U)) & ~(BLOCK_ALIGN - 1U));
161 }
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:759
static const size_t BLOCK_ALIGN
Minimum block alignment in bytes: sizeof(MemoryBlock).

References BLOCK_ALIGN, and stk::Max().

Referenced by BlockMemoryPool(), BlockMemoryPool(), MsgBufSlotCount(), osMemoryPoolNew(), stk_blockpool_create_static(), tx_block_pool_create(), xMessageBufferCreateStatic(), xMessageBufferCreateStaticWithCallback(), and xMessageBufferCreateWithCallback().

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

◆ Alloc()

void * stk::memory::BlockMemoryPool::Alloc ( )
inline

Allocate one block, blocking indefinitely until one is available.

Returns
Pointer to an uninitialized block. Returns nullptr only if the wait was cancelled via IKernel::CancelTaskWait(); never on timeout (there is none). Use TimedAllocEx() if cancellation must be told apart from other failures.
Warning
ISR-unsafe.

Definition at line 514 of file stk_memory_blockpool.h.

515{
517}
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:228
void * TimedAlloc(Timeout timeout_ticks=WAIT_INFINITE)
Allocate one block, blocking until one becomes available or the timeout expires.

References TimedAlloc(), and stk::WAIT_INFINITE.

Referenced by stk_blockpool_alloc().

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

◆ AllocT()

template<typename T>
T * stk::memory::BlockMemoryPool::AllocT ( )
inline

Allocate one typed block, blocking indefinitely until one is available.

Returns
Typed pointer. Returns nullptr only if the wait was cancelled (see Alloc()).
Warning
ISR-unsafe.

Definition at line 520 of file stk_memory_blockpool.h.

521{
523}
T * TimedAllocT(Timeout timeout_ticks=WAIT_INFINITE)
Allocate one typed block, blocking until one becomes available or the timeout expires.

References TimedAllocT(), and stk::WAIT_INFINITE.

Here is the call graph for this function:

◆ BuildFreeList()

void stk::memory::BlockMemoryPool::BuildFreeList ( )
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 610 of file stk_memory_blockpool.h.

611{
613
614 m_free_list = nullptr;
615 m_used_count = 0U;
616
617 // Link blocks in reverse order so m_free_list ends up pointing at block_0
618 // (lowest address), giving ascending allocation order.
619 for (size_t i = m_capacity; i-- > 0U; )
620 {
622
623 blk->next = m_free_list;
624 m_free_list = blk;
625 }
626}
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:231
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:214
Intrusive free-list node overlaid on the first word of every free block.

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().

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

◆ Free()

bool stk::memory::BlockMemoryPool::Free ( void * ptr)
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, so it can re-check for a free block. Under contention from TryAlloc() (including from another task or an ISR racing in before the woken task is scheduled), that task may find the block already taken and continue waiting rather than being guaranteed one on this wake.

Parameters
[in]ptrPointer 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.
Returns
true - block successfully returned. false - ptr is nullptr, out of range, or misaligned; each case indicates a caller logic error.
Note
ISR-safe.
Warning
Double-free is not detected and will silently corrupt the free-list. Null the pointer after Free() to prevent this.

Definition at line 540 of file stk_memory_blockpool.h.

541{
542 bool success = false;
543
544 if (ptr != nullptr)
545 {
546 // bounds check: ptr must be in range [m_storage, m_storage + capacity * block_size)
547 const Word pt = hw::PtrToWord(ptr);
548 const Word lo = hw::PtrToWord(m_storage);
549 const Word hi = lo + (m_capacity * m_block_size);
550
551 if ((pt < lo) || (pt >= hi))
552 {
553 STK_ASSERT(false); // API contract: ptr does not belong to this pool
554 }
555 // alignment check: ptr must be at the start of a block boundary
556 else if ((static_cast<size_t>(pt - lo) % m_block_size) != 0U)
557 {
558 STK_ASSERT(false); // API contract: ptr is misaligned (not a block start)
559 }
560 else
561 {
562 const sync::ScopedCriticalSection cs_;
563
564 if (m_used_count == 0U)
565 {
566 STK_ASSERT(false); // pool is already fully free - definite double-free
567 }
568 else
569 {
570 #if defined(_DEBUG) || defined(DEBUG)
571 bool is_double_free = false;
572
573 // O(n) double-free detection: walk the free-list and check if ptr is already on it,
574 // only active in debug builds - compiles away completely in release
575 for (const MemoryBlock *node = m_free_list; (node != nullptr); node = node->next)
576 {
577 if (node == reinterpret_cast<const MemoryBlock *>(ptr))
578 {
579 STK_ASSERT(false); // double-free: ptr is already on the free-list
580 is_double_free = true;
581 break;
582 }
583 }
584
585 if (!is_double_free)
586 #endif
587 {
588 // push block onto free-list head (O(1))
589 auto *const blk = reinterpret_cast<MemoryBlock *>(ptr);
590 blk->next = m_free_list;
591 m_free_list = blk;
592 m_used_count = (m_used_count - 1U);
593
594 // wake one blocked allocator - true scheduler wait, no spin-yield
595 m_cv.NotifyOne_CS();
596
597 success = true;
598 }
599 }
600 }
601 }
602
603 return success;
604}
uintptr_t Word
Native processor word type.
Definition stk_common.h:160
sync::ConditionVariable m_cv
signalled by Free() to wake one task blocked in TimedAlloc()
MemoryBlock * next
next free block in the list, or nullptr if this is the last one

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(), tx_block_release(), xMessageBufferReceive(), xMessageBufferReceiveFromISR(), xMessageBufferReset(), xMessageBufferResetFromISR(), xMessageBufferSend(), and xMessageBufferSendFromISR().

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

◆ GetBlockSize()

size_t stk::memory::BlockMemoryPool::GetBlockSize ( ) const
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().

Returns
Aligned block size in bytes.
Note
ISR-safe.

Definition at line 279 of file stk_memory_blockpool.h.

279{ return m_block_size; }

References m_block_size.

Referenced by osMemoryPoolGetBlockSize(), and stk_blockpool_get_block_size().

Here is the caller graph for this function:

◆ GetCapacity()

size_t stk::memory::BlockMemoryPool::GetCapacity ( ) const
inline

Get the total block capacity of the pool.

Returns
Maximum number of blocks that can be simultaneously allocated. Matches osMemoryPoolGetCapacity().
Note
ISR-safe.

Definition at line 271 of file stk_memory_blockpool.h.

271{ return m_capacity; }

References m_capacity.

Referenced by stk_blockpool_get_capacity(), and tx_block_pool_info_get().

Here is the caller graph for this function:

◆ GetFreeCount()

size_t stk::memory::BlockMemoryPool::GetFreeCount ( ) const
inline

Get the number of free (available) blocks.

Returns
Point-in-time snapshot of GetCapacity() - GetUsedCount(). Matches osMemoryPoolGetSpace().
Note
ISR-safe.

Definition at line 293 of file stk_memory_blockpool.h.

293{ return (m_capacity - m_used_count); }

References m_capacity, and m_used_count.

Referenced by IsFull(), stk_blockpool_get_free_count(), and tx_block_pool_info_get().

Here is the caller graph for this function:

◆ GetTraceName()

const char * stk::ITraceable::GetTraceName ( ) const
inlineinherited

Get name.

Returns
Name string, or NULL if not set or if STK_SYNC_DEBUG_NAMES is 0.

Definition at line 582 of file stk_common.h.

583 {
584 #if STK_SYNC_DEBUG_NAMES
585 return m_trace_name;
586 #else
587 return nullptr;
588 #endif
589 }

◆ GetUsedCount()

size_t stk::memory::BlockMemoryPool::GetUsedCount ( ) const
inline

Get the number of currently allocated (outstanding) blocks.

Returns
Point-in-time snapshot. Matches osMemoryPoolGetCount().
Note
May be stale immediately after return in a multi-task environment.
ISR-safe on targets where an aligned size_t read is a single instruction.

Definition at line 286 of file stk_memory_blockpool.h.

286{ return m_used_count; }

References m_used_count.

Referenced by stk_blockpool_get_used_count().

Here is the caller graph for this function:

◆ IsEmpty()

bool stk::memory::BlockMemoryPool::IsEmpty ( ) const
inline

Check whether all blocks are free (no outstanding allocations).

Returns
true if no blocks are currently allocated.
Note
ISR-safe.

Definition at line 305 of file stk_memory_blockpool.h.

305{ return (m_used_count == 0U); }

References m_used_count.

Referenced by stk_blockpool_is_empty().

Here is the caller graph for this function:

◆ IsFull()

bool stk::memory::BlockMemoryPool::IsFull ( ) const
inline

Check whether all blocks are currently allocated (pool exhausted).

Returns
true if no blocks are available for allocation.
Note
ISR-safe.

Definition at line 299 of file stk_memory_blockpool.h.

299{ return (GetFreeCount() == 0U); }
size_t GetFreeCount() const
Get the number of free (available) blocks.

References GetFreeCount().

Referenced by stk_blockpool_is_full().

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

◆ IsStorageValid()

bool stk::memory::BlockMemoryPool::IsStorageValid ( ) const
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).

Returns
true if the pool is ready for use.
Note
ISR-safe.

Definition at line 264 of file stk_memory_blockpool.h.

264{ return (m_storage != nullptr); }

References m_storage.

Referenced by osMemoryPoolNew(), stk_blockpool_is_storage_valid(), and xMessageBufferCreate().

Here is the caller graph for this function:

◆ PopFreeList()

void * stk::memory::BlockMemoryPool::PopFreeList ( )
inlineprivate

Pop the head block from the free-list, increment m_used_count, and return it.

Note
Caller must hold a critical section and ensure m_free_list != nullptr.

Definition at line 628 of file stk_memory_blockpool.h.

629{
631
632 MemoryBlock *const blk = m_free_list;
633
634 m_free_list = blk->next;
635 m_used_count = (m_used_count + 1U);
636
637 return blk;
638}

References m_capacity, m_free_list, m_used_count, stk::memory::BlockMemoryPool::MemoryBlock::next, and STK_ASSERT.

Referenced by TimedAllocEx().

Here is the caller graph for this function:

◆ SetTraceName()

void stk::ITraceable::SetTraceName ( const char * name)
inlineinherited

Set name.

Parameters
[in]nameNull-terminated string or NULL.
Note
If STK_SYNC_DEBUG_NAMES is 0 then calling this function has no effect.

Definition at line 570 of file stk_common.h.

571 {
572 #if STK_SYNC_DEBUG_NAMES
573 m_trace_name = name;
574 #else
575 STK_UNUSED(name);
576 #endif
577 }

References STK_UNUSED.

Referenced by stk::memory::BlockMemoryPool::BlockMemoryPool(), stk::memory::BlockMemoryPool::BlockMemoryPool(), stk::memory::BytePool::BytePool(), stk::memory::BytePool::BytePool(), tx_block_pool_create(), tx_event_flags_create(), tx_mutex_create(), tx_queue_create(), and tx_semaphore_create().

Here is the caller graph for this function:

◆ STK_NONCOPYABLE_CLASS()

stk::memory::BlockMemoryPool::STK_NONCOPYABLE_CLASS ( BlockMemoryPool )
private

References BlockMemoryPool().

Here is the call graph for this function:

◆ TimedAlloc()

void * stk::memory::BlockMemoryPool::TimedAlloc ( Timeout timeout_ticks = WAIT_INFINITE)
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().

Parameters
[in]timeout_ticksMaximum time to wait (ticks). WAIT_INFINITE - block indefinitely (default). NO_WAIT - return nullptr immediately if pool is empty (identical to TryAlloc(); ISR-safe).
Returns
Pointer to an uninitialized block of at least GetBlockSize() bytes, or nullptr if the timeout expired or the wait was cancelled via IKernel::CancelTaskWait() before a block became available.
Note
Collapses timeout and cancellation. Use TimedAllocEx() to tell them apart.
Warning
ISR-safe only when timeout_ticks = NO_WAIT; ISR-unsafe otherwise.

Definition at line 494 of file stk_memory_blockpool.h.

495{
496 void *block = nullptr;
497
498 if (TimedAllocEx(&block, timeout_ticks) != WAIT_RESULT_SIGNAL)
499 {
500 block = nullptr;
501 }
502
503 return block;
504}
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
Definition stk_common.h:139
EWaitResult TimedAllocEx(void **block, Timeout timeout_ticks=WAIT_INFINITE)
Allocate one block, preserving the full wait outcome.

References TimedAllocEx(), and stk::WAIT_RESULT_SIGNAL.

Referenced by Alloc(), stk_blockpool_timed_alloc(), TimedAllocT(), TryAlloc(), xMessageBufferSend(), and xMessageBufferSendFromISR().

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

◆ TimedAllocEx()

EWaitResult stk::memory::BlockMemoryPool::TimedAllocEx ( void ** block,
Timeout timeout_ticks = WAIT_INFINITE )
inline

Allocate one block, preserving the full wait outcome.

Identical to TimedAlloc(), except the caller gets the raw EWaitResult so a cancellation (via IKernel::CancelTaskWait()) can be distinguished from a timeout. Mirrors sync::Event::WaitEx().

Parameters
[out]blockReceives the allocated block on WAIT_RESULT_SIGNAL, nullptr on any other result. Must not be nullptr.
[in]timeout_ticksSame as TimedAlloc().
Returns
WAIT_RESULT_SIGNAL - a block was allocated (immediately or after waiting), WAIT_RESULT_TIMEOUT - no block became available before the timeout (or NO_WAIT was passed on an empty pool); a block freed at the very moment the timeout expired is still returned as SIGNAL, WAIT_RESULT_CANCELED - the wait was cancelled, nothing was allocated, WAIT_RESULT_FAIL - invalid arguments or the kernel rejected the wait.
Warning
ISR-safe only when timeout_ticks = NO_WAIT; ISR-unsafe otherwise.

Definition at line 427 of file stk_memory_blockpool.h.

428{
430
431 STK_ASSERT(block != nullptr); // API contract: output pointer must be valid
432
433 if (block == nullptr)
434 {
435 // result is WAIT_RESULT_FAIL already, so noop
436 }
437 else if (hw::IsInsideISR() && (timeout_ticks != NO_WAIT))
438 {
439 STK_ASSERT(false); // API contract: ISR callers must pass NO_WAIT / use TryAlloc()
440 *block = nullptr;
441 }
442 else
443 {
444 sync::ScopedCriticalSection cs_;
445
446 const bool timed_wait = (timeout_ticks != WAIT_INFINITE) && (timeout_ticks != NO_WAIT);
447
448 // capture an absolute deadline once, before entering the wait loop; a different
449 // allocator (TryAlloc() from another task or an ISR) can steal the just-freed
450 // block between NotifyOne_CS() and this task re-acquiring the critical section
451 // (Mesa-style wakeup, not a direct handoff - see Free()'s note), so re-passing
452 // the original timeout_ticks on each retry would silently restart it;
453 // kept as 64-bit Ticks (not truncated to Timeout) so it can't wrap on long uptimes
454 const Ticks deadline = (timed_wait ? (GetTicks() + static_cast<Ticks>(timeout_ticks)) : 0);
455
456 *block = nullptr;
457 result = WAIT_RESULT_SIGNAL; // fast path: a block is already available
458
459 while (m_free_list == nullptr)
460 {
461 Timeout remaining = timeout_ticks;
462 if (timed_wait)
463 {
464 const Ticks left = (deadline - GetTicks());
465 remaining = ((left > 0) ? static_cast<Timeout>(left) : NO_WAIT);
466 }
467
468 // Atomically release the critical section, suspend the task, and
469 // re-acquire before returning - no CPU cycles wasted while waiting.
470 result = m_cv.WaitEx(cs_, remaining);
471 if (result != WAIT_RESULT_SIGNAL)
472 {
473 break; // timeout, cancellation or kernel failure: report as is
474 }
475 }
476
477 // timeout raced with a Free(): the lock was re-acquired and a block is available,
478 // so honor it instead of reporting a failure (cancellation is never overridden)
479 if ((result == WAIT_RESULT_TIMEOUT) && (m_free_list != nullptr))
480 {
481 result = WAIT_RESULT_SIGNAL;
482 }
483
484 // only allocate a block if the wait ended in a signal (or none was needed)
485 if (result == WAIT_RESULT_SIGNAL)
486 {
487 *block = PopFreeList();
488 }
489 }
490
491 return result;
492}
EWaitResult
Wait result (see IKernelService::Wait).
Definition stk_common.h:137
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
Definition stk_common.h:138
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:140
int64_t Ticks
Ticks value.
Definition stk_common.h:175
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:170
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:452
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
void * PopFreeList()
Pop the head block from the free-list, increment m_used_count, and return it.

References stk::GetTicks(), stk::hw::IsInsideISR(), m_cv, m_free_list, stk::NO_WAIT, PopFreeList(), STK_ASSERT, stk::WAIT_INFINITE, stk::WAIT_RESULT_FAIL, stk::WAIT_RESULT_SIGNAL, and stk::WAIT_RESULT_TIMEOUT.

Referenced by TimedAlloc(), and tx_block_allocate().

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

◆ TimedAllocT()

template<typename T>
T * stk::memory::BlockMemoryPool::TimedAllocT ( Timeout timeout_ticks = WAIT_INFINITE)
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.

Parameters
[in]timeout_ticksMaximum time to wait (ticks). Same semantics as TimedAlloc().
Returns
Typed pointer, or nullptr if the timeout expired.
Warning
ISR-safe only when timeout_ticks = NO_WAIT; ISR-unsafe otherwise.

Definition at line 507 of file stk_memory_blockpool.h.

508{
509 STK_ASSERT(sizeof(T) <= m_block_size); // API contract: block size should larger or equal to object's size
510
511 return static_cast<T *>(TimedAlloc(timeout_ticks));
512}

References m_block_size, STK_ASSERT, and TimedAlloc().

Referenced by AllocT(), and TryAllocT().

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

◆ TryAlloc()

void * stk::memory::BlockMemoryPool::TryAlloc ( )
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.

Returns
Pointer to an uninitialized block, or nullptr if the pool is empty.
Note
ISR-safe.

Definition at line 525 of file stk_memory_blockpool.h.

526{
527 return TimedAlloc(NO_WAIT);
528}

References stk::NO_WAIT, and TimedAlloc().

Referenced by stk_blockpool_try_alloc().

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

◆ TryAllocT()

template<typename T>
T * stk::memory::BlockMemoryPool::TryAllocT ( )
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.

Returns
Typed pointer, or nullptr if the pool is empty.
Note
ISR-safe.

Definition at line 531 of file stk_memory_blockpool.h.

532{
533 return TimedAllocT<T>(NO_WAIT);
534}

References stk::NO_WAIT, and TimedAllocT().

Here is the call graph for this function:

Member Data Documentation

◆ BLOCK_ALIGN

const size_t stk::memory::BlockMemoryPool::BLOCK_ALIGN = static_cast<size_t>(sizeof(MemoryBlock))
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 324 of file stk_memory_blockpool.h.

Referenced by AlignBlockSize(), and BuildFreeList().

◆ CAPACITY_MAX

const size_t stk::memory::BlockMemoryPool::CAPACITY_MAX = 0xFFFEU
static

Max capacity supported (number of blocks).

Definition at line 101 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), and tx_block_pool_create().

◆ m_block_size

size_t stk::memory::BlockMemoryPool::m_block_size
private

aligned block size in bytes (>= BLOCK_ALIGN)

Definition at line 342 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), GetBlockSize(), TimedAllocT(), and ~BlockMemoryPool().

◆ m_capacity

size_t stk::memory::BlockMemoryPool::m_capacity
private

◆ m_cv

sync::ConditionVariable stk::memory::BlockMemoryPool::m_cv
private

signalled by Free() to wake one task blocked in TimedAlloc()

Definition at line 341 of file stk_memory_blockpool.h.

Referenced by Free(), and TimedAllocEx().

◆ m_free_list

MemoryBlock* stk::memory::BlockMemoryPool::m_free_list
private

head of the intrusive free-list (nullptr when pool is empty)

Definition at line 340 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), PopFreeList(), and TimedAllocEx().

◆ m_storage

uint8_t* stk::memory::BlockMemoryPool::m_storage
private

flat byte array holding all N blocks (owned or external)

Definition at line 339 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), IsStorageValid(), and ~BlockMemoryPool().

◆ m_storage_owned

bool stk::memory::BlockMemoryPool::m_storage_owned
private

true -> storage is heap-allocated; free in destructor

Definition at line 345 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), and ~BlockMemoryPool().

◆ m_used_count

size_t stk::memory::BlockMemoryPool::m_used_count
private

number of blocks currently allocated (outstanding)

Definition at line 344 of file stk_memory_blockpool.h.

Referenced by BlockMemoryPool(), BlockMemoryPool(), BuildFreeList(), Free(), GetFreeCount(), GetUsedCount(), IsEmpty(), and PopFreeList().


The documentation for this class was generated from the following file: