10#ifndef STK_MEMORY_BLOCKPOOL_H_
11#define STK_MEMORY_BLOCKPOOL_H_
123 size_t storage_size,
const char *name =
nullptr);
137 explicit BlockMemoryPool(
size_t capacity,
size_t raw_block_size,
const char *name =
nullptr);
328inline BlockMemoryPool::BlockMemoryPool(
size_t capacity,
size_t raw_block_size, uint8_t *storage,
329 size_t storage_size,
const char *name)
344#if STK_SYNC_DEBUG_NAMES
353inline BlockMemoryPool::BlockMemoryPool(
size_t capacity,
size_t raw_block_size,
const char *name)
354 : m_storage(new (std::nothrow) uint8_t[capacity * AlignBlockSize(raw_block_size)]),
355 m_free_list(nullptr),
356 m_block_size(AlignBlockSize(raw_block_size)),
357 m_capacity(capacity),
359 m_storage_owned(true)
365#if STK_SYNC_DEBUG_NAMES
376inline BlockMemoryPool::~BlockMemoryPool()
390inline void *BlockMemoryPool::TimedAlloc(
Timeout timeout)
400 while (m_free_list ==
nullptr)
412inline T *BlockMemoryPool::TimedAllocT(
Timeout timeout)
419inline void *BlockMemoryPool::Alloc()
425inline T *BlockMemoryPool::AllocT()
430inline void *BlockMemoryPool::TryAlloc()
436inline T *BlockMemoryPool::TryAllocT()
438 return TimedAllocT<T>(
NO_WAIT);
445inline bool BlockMemoryPool::Free(
void *ptr)
451 const uint8_t *p8 =
static_cast<uint8_t *
>(ptr);
455 if ((p8 < lo) || (p8 >= hi))
462 if ((
static_cast<size_t>(p8 - lo) % m_block_size) != 0U)
470 if (m_used_count == 0U)
476#if defined(_DEBUG) || defined(DEBUG)
479 for (
const MemoryBlock *node = m_free_list; (node !=
nullptr); node = node->next)
481 if (node ==
reinterpret_cast<const MemoryBlock *
>(ptr))
490 auto *blk =
reinterpret_cast<MemoryBlock *
>(ptr);
505inline void BlockMemoryPool::BuildFreeList()
514 for (
size_t i = m_capacity; i-- > 0U; )
523inline void *BlockMemoryPool::PopFreeList()
Contains interface definitions of the library.
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Contains helper implementations which simplify user-side code.
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
int32_t Timeout
Timeout time (ticks).
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Memory-related primitives.
bool m_storage_owned
true -> storage is heap-allocated; free in destructor
uint8_t * m_storage
flat byte array holding all N blocks (owned or external)
void * Alloc()
Allocate one block, blocking indefinitely until one is available.
sync::ConditionVariable m_cv
signalled by Free() to wake one task blocked in TimedAlloc()
static constexpr size_t AlignBlockSize(size_t raw_size)
Round a raw block size up to the nearest multiple of BLOCK_ALIGN.
uint16_t m_used_count
number of blocks currently allocated (outstanding)
T * AllocT()
Allocate one typed block, blocking indefinitely until one is available.
void * PopFreeList()
Pop the head block from the free-list, increment m_used_count, and return it.
T * TimedAllocT(Timeout timeout=WAIT_INFINITE)
Allocate one typed block, blocking until one becomes available or the timeout expires.
~BlockMemoryPool()
Destructor.
size_t m_capacity
total number of blocks
MemoryBlock * m_free_list
head of the intrusive free-list (nullptr when pool is empty)
size_t GetFreeCount() const
Get the number of free (available) blocks.
void BuildFreeList()
Initialise the intrusive free-list across m_storage.
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.
static const size_t CAPACITY_MAX
bool Free(void *ptr)
Return a previously allocated block to the pool.
T * TryAllocT()
Non-blocking typed allocation attempt.
void * TimedAlloc(Timeout timeout=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.
bool IsEmpty() const
Check whether all blocks are free (no outstanding allocations).
size_t GetCapacity() const
Get the total block capacity of the pool.
static const uint32_t BLOCK_ALIGN
Minimum block alignment in bytes: sizeof(MemoryBlock).
size_t GetUsedCount() const
Get the number of currently allocated (outstanding) blocks.
bool IsFull() const
Check whether all blocks are currently allocated (pool exhausted).
size_t m_block_size
aligned block size in bytes (>= BLOCK_ALIGN)
bool IsStorageValid() const
Verify that the backing storage is valid and the pool is ready for use.
void * TryAlloc()
Non-blocking allocation attempt.
__stk_forceinline Word PtrToWord(T *ptr) noexcept
Cast a pointer to a CPU register-width integer.
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Intrusive free-list node overlaid on the first word of every free block.
MemoryBlock * next
next free block in the list, or nullptr if this is the last one
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Condition Variable primitive for signaling between tasks based on specific predicates.
void NotifyOne_CS()
Wake one waiting task.
bool Wait(IMutex &mutex, Timeout timeout=WAIT_INFINITE)
Wait for a signal.
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics.