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::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.
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)
MemoryBlockm_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).

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
}
}
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:210
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 327 of file stk_memory_blockpool.h.

329: m_storage(storage),
330 m_free_list(nullptr),
331 m_block_size(AlignBlockSize(raw_block_size)),
332 m_capacity(capacity),
333 m_used_count(0U),
334 m_storage_owned(false)
335{
336 STK_ASSERT(capacity > 0U);
337 STK_ASSERT(capacity <= CAPACITY_MAX);
338 STK_ASSERT(raw_block_size > 0U);
339 STK_ASSERT(storage != nullptr);
340
341 // API contract: caller-supplied buffer must be large enough
342 STK_ASSERT(storage_size >= (capacity * m_block_size));
343
344 // in Release builds we ensure capacity which fits storage size, in Debug build the assertion above will be hit
345 if ((capacity * m_block_size) > storage_size)
346 {
347 m_capacity = storage_size / m_block_size;
348 }
349
350#if STK_SYNC_DEBUG_NAMES
351 SetTraceName(name);
352#else
353 STK_UNUSED(name);
354#endif
355
357}
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
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:421

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 operator new (std::nothrow). 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 360 of file stk_memory_blockpool.h.

362 m_free_list(nullptr),
363 m_block_size(AlignBlockSize(raw_block_size)),
364 m_capacity(capacity),
365 m_used_count(0U),
366 m_storage_owned(true)
367{
368 STK_ASSERT(capacity > 0U);
369 STK_ASSERT(capacity <= CAPACITY_MAX);
370 STK_ASSERT(raw_block_size > 0U);
371
372#if STK_SYNC_DEBUG_NAMES
373 SetTraceName(name);
374#else
375 STK_UNUSED(name);
376#endif
377
378 if (m_storage != nullptr)
379 {
381 }
382 // else: m_free_list remains nullptr; caller must check IsStorageValid()
383}
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 386 of file stk_memory_blockpool.h.

387{
388 // ConditionVariable destructor asserts the wait list is empty
389#if STK_MEMORY_PLACEMENT_NEW
390 if (m_storage_owned)
391 {
393 m_storage = nullptr;
394 }
395#endif
396}
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.

Here is the call 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)
Compile-time maximum of two values.
Definition stk_defs.h:645
static const uint32_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(), 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. Never returns nullptr.
Warning
ISR-unsafe.

Definition at line 444 of file stk_memory_blockpool.h.

445{
447}
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:204
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. Never returns nullptr.
Warning
ISR-unsafe.

Definition at line 450 of file stk_memory_blockpool.h.

451{
453}
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 540 of file stk_memory_blockpool.h.

541{
543
544 m_free_list = nullptr;
545 m_used_count = 0U;
546
547 // Link blocks in reverse order so m_free_list ends up pointing at block_0
548 // (lowest address), giving ascending allocation order.
549 for (size_t i = m_capacity; i-- > 0U; )
550 {
552
553 blk->next = m_free_list;
554 m_free_list = blk;
555 }
556}
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:123
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:106
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. The woken task is guaranteed to find a free block available.

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 470 of file stk_memory_blockpool.h.

471{
472 bool success = false;
473
474 if (ptr != nullptr)
475 {
476 // bounds check: ptr must be in range [m_storage, m_storage + capacity * block_size)
477 const Word pt = hw::PtrToWord(ptr);
478 const Word lo = hw::PtrToWord(m_storage);
479 const Word hi = lo + (m_capacity * m_block_size);
480
481 if ((pt < lo) || (pt >= hi))
482 {
483 STK_ASSERT(false); // API contract: ptr does not belong to this pool
484 }
485 // alignment check: ptr must be at the start of a block boundary
486 else if ((static_cast<size_t>(pt - lo) % m_block_size) != 0U)
487 {
488 STK_ASSERT(false); // API contract: ptr is misaligned (not a block start)
489 }
490 else
491 {
492 const sync::ScopedCriticalSection cs_;
493
494 if (m_used_count == 0U)
495 {
496 STK_ASSERT(false); // pool is already fully free - definite double-free
497 }
498 else
499 {
500 #if defined(_DEBUG) || defined(DEBUG)
501 bool is_double_free = false;
502
503 // O(n) double-free detection: walk the free-list and check if ptr is already on it,
504 // only active in debug builds - compiles away completely in release
505 for (const MemoryBlock *node = m_free_list; (node != nullptr); node = node->next)
506 {
507 if (node == reinterpret_cast<const MemoryBlock *>(ptr))
508 {
509 STK_ASSERT(false); // double-free: ptr is already on the free-list
510 is_double_free = true;
511 break;
512 }
513 }
514
515 if (!is_double_free)
516 #endif
517 {
518 // push block onto free-list head (O(1))
519 auto *const blk = reinterpret_cast<MemoryBlock *>(ptr);
520 blk->next = m_free_list;
521 m_free_list = blk;
522 m_used_count = static_cast<uint16_t>(m_used_count - 1U);
523
524 // wake one blocked allocator - true scheduler wait, no spin-yield
525 m_cv.NotifyOne_CS();
526
527 success = true;
528 }
529 }
530 }
531 }
532
533 return success;
534}
uintptr_t Word
Native processor word type.
Definition stk_common.h:136
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(), 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 254 of file stk_memory_blockpool.h.

254{ 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 246 of file stk_memory_blockpool.h.

246{ return m_capacity; }

References m_capacity.

Referenced by stk_blockpool_get_capacity().

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 268 of file stk_memory_blockpool.h.

268{ return (m_capacity - m_used_count); }

References m_capacity, and m_used_count.

Referenced by IsFull(), and stk_blockpool_get_free_count().

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 433 of file stk_common.h.

434 {
435 #if STK_SYNC_DEBUG_NAMES
436 return m_trace_name;
437 #else
438 return nullptr;
439 #endif
440 }

◆ 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 a 16-bit aligned read is a single instruction.

Definition at line 261 of file stk_memory_blockpool.h.

261{ 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 280 of file stk_memory_blockpool.h.

280{ 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 274 of file stk_memory_blockpool.h.

274{ 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 239 of file stk_memory_blockpool.h.

239{ 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 558 of file stk_memory_blockpool.h.

559{
561
562 MemoryBlock *const blk = m_free_list;
563
564 m_free_list = blk->next;
565 m_used_count = static_cast<uint16_t>(m_used_count + 1U);
566
567 return blk;
568}

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

Referenced by TimedAlloc().

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 421 of file stk_common.h.

422 {
423 #if STK_SYNC_DEBUG_NAMES
424 m_trace_name = name;
425 #else
426 STK_UNUSED(name);
427 #endif
428 }

References STK_UNUSED.

Referenced by stk::memory::BlockMemoryPool::BlockMemoryPool(), and stk::memory::BlockMemoryPool::BlockMemoryPool().

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 GetRawBlockSize() bytes, or nullptr if the timeout expired before a block became available.
Warning
ISR-safe only when timeout_ticks = NO_WAIT; ISR-unsafe otherwise.

Definition at line 402 of file stk_memory_blockpool.h.

403{
404 void *block = nullptr;
405
406 if (!hw::IsInsideISR() || (timeout_ticks == NO_WAIT))
407 {
408 sync::ScopedCriticalSection cs_;
409 bool is_timeout = false;
410
411 while (m_free_list == nullptr)
412 {
413 // Atomically release the critical section, suspend the task, and
414 // re-acquire before returning - no CPU cycles wasted while waiting.
415 if (!m_cv.Wait(cs_, timeout_ticks))
416 {
417 is_timeout = true; // timeout expired
418 break;
419 }
420 }
421
422 // only allocate a block if we didn't time out
423 if (!is_timeout)
424 {
425 block = PopFreeList();
426 }
427 }
428 else
429 {
430 STK_ASSERT(false); // API contract: ISR callers must pass NO_WAIT / use TryAlloc()
431 }
432
433 return block;
434}
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::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().

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 437 of file stk_memory_blockpool.h.

438{
439 STK_ASSERT(sizeof(T) <= m_block_size); // API contract: block size should larger or equal to object's size
440
441 return static_cast<T *>(TimedAlloc(timeout_ticks));
442}

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 455 of file stk_memory_blockpool.h.

456{
457 return TimedAlloc(NO_WAIT);
458}

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 461 of file stk_memory_blockpool.h.

462{
463 return TimedAllocT<T>(NO_WAIT);
464}

References stk::NO_WAIT, and TimedAllocT().

Here is the call graph for this function:

Member Data Documentation

◆ BLOCK_ALIGN

const uint32_t stk::memory::BlockMemoryPool::BLOCK_ALIGN = static_cast<uint32_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 299 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(), and BlockMemoryPool().

◆ m_block_size

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

◆ 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 316 of file stk_memory_blockpool.h.

Referenced by Free(), and TimedAlloc().

◆ 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 315 of file stk_memory_blockpool.h.

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

◆ m_storage

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

◆ m_storage_owned

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

◆ m_used_count

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


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