10#ifndef STK_MEMORY_BYTEPOOL_H_
11#define STK_MEMORY_BYTEPOOL_H_
128 explicit BytePool(uint8_t *storage,
size_t storage_size,
const char *name =
nullptr);
139#if STK_MEMORY_PLACEMENT_NEW
140 explicit BytePool(
size_t storage_size,
const char *name =
nullptr);
225 void *
Alloc(
size_t size);
231 template <
typename T> T *
AllocT();
264 bool Free(
void *ptr);
276 void GetInfo(
size_t &available,
size_t &largest,
size_t &fragments)
const;
293 return ((
m_first !=
nullptr) ?
static_cast<size_t>(
294 reinterpret_cast<const uint8_t *
>(
m_end) -
reinterpret_cast<const uint8_t *
>(
m_first)) : 0U);
347 return reinterpret_cast<BlockHeader *
>(
const_cast<uint8_t *
>(
reinterpret_cast<const uint8_t *
>(h)) + h->
size);
355 bool IsSane(
const BlockHeader *h)
const;
376 static void AccountRun(
size_t run,
size_t &available,
size_t &largest,
size_t &fragments);
401#if STK_SYNC_DEBUG_NAMES
410#if STK_MEMORY_PLACEMENT_NEW
421#if STK_SYNC_DEBUG_NAMES
435#if STK_MEMORY_PLACEMENT_NEW
457 if (block ==
nullptr)
487 const Ticks deadline = (timed_wait ? (
GetTicks() +
static_cast<Ticks>(timeout_ticks)) : 0);
492 while (ptr ==
nullptr)
494 Timeout remaining = timeout_ticks;
510 remaining =
static_cast<Timeout>(left);
515 result =
m_cv.WaitEx(cs_, remaining);
548 void *block =
nullptr;
563 return static_cast<T *
>(
TimedAlloc(
sizeof(T), timeout_ticks));
594 bool success =
false;
596 if ((ptr !=
nullptr) && (
m_first !=
nullptr))
608 else if ((
static_cast<size_t>(pt - lo) %
BLOCK_ALIGN) != 0U)
624 bool is_block =
true;
626 #if defined(_DEBUG) || defined(DEBUG)
634 if (is_block &&
IsSane(h))
684 AccountRun(run, available, largest, fragments);
689 AccountRun(run, available, largest, fragments);
705 const size_t shift = (
AlignSize(addr) - addr);
719 m_first->size =
static_cast<uint32_t
>(usable);
732 (
static_cast<size_t>(
reinterpret_cast<const uint8_t *
>(
m_end) -
reinterpret_cast<const uint8_t *
>(h)) >= h->
size));
749 void *result =
nullptr;
765 const size_t rest = (h->size - need);
771 tail->
size =
static_cast<uint32_t
>(rest);
774 h->size =
static_cast<uint32_t
>(need);
808 available += payload;
811 if (payload > largest)
Weak declaration of memory allocator: stk::memory::MemoryAllocator.
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Implementation of synchronization primitive: stk::sync::ConditionVariable.
Namespace of STK package.
uintptr_t Word
Native processor word type.
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
EWaitResult
Wait result (see IKernelService::Wait).
@ WAIT_RESULT_FAIL
IKernelService::Wait returned with error without waiting.
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
@ WAIT_RESULT_SIGNAL
The wake was caused by a signal.
int64_t Ticks
Ticks value.
int32_t Timeout
Timeout time (ticks).
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
static constexpr Word PtrToWord(T *const 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).
Memory-related primitives.
Memory allocator for allocating dynamic memory.
static void FreeArrayT(TElement ptr[], size_t count)
Destroy and free an array allocated via AllocateT().
static const uint32_t STATE_USED
"USED"
BlockHeader * m_end
one past the last block (aligned), nullptr if the pool is invalid
static const uint32_t STATE_FREE
"FREE"
static const uint32_t STATE_NONE
stale header absorbed by a merge
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.
sync::ConditionVariable m_cv
signalled by Free() to wake tasks blocked in TimedAlloc()
bool IsBlockStart(const BlockHeader *h) const
Check that h is the header of an existing block (walks the list from the start).
bool IsSane(const BlockHeader *h) const
Check that the header h (which must be inside the pool) looks intact.
size_t GetMaxRequest() const
Get the largest request that can ever succeed on this pool.
STK_NONCOPYABLE_CLASS(BytePool)
T * AllocT()
Allocate one typed block, blocking indefinitely until memory is available.
static const size_t HEADER_SIZE
Size of the per-block header in bytes.
T * TryAllocT()
Non-blocking typed allocation attempt.
static const size_t MIN_BLOCK_SIZE
Smallest block: a header plus the minimum payload (BLOCK_ALIGN).
static const size_t POOL_SIZE_MAX
Largest managed area: block sizes are stored as 32-bit values.
EWaitResult TimedAllocEx(void **block, size_t size, Timeout timeout_ticks=WAIT_INFINITE)
Allocate a block, preserving the full wait outcome.
size_t m_storage_size
size of the raw storage in bytes
uint8_t * m_storage
raw storage as supplied or allocated (before alignment)
static BlockHeader * Next(const BlockHeader *h)
Get the header of the block that follows h.
void * FindFree(size_t need)
Find (and claim) the first free block that can hold need bytes.
size_t GetSize() const
Get the total size of the managed (aligned) area in bytes, headers included.
void * Alloc(size_t size)
Allocate a block, blocking indefinitely until memory is available.
void GetInfo(size_t &available, size_t &largest, size_t &fragments) const
Collect pool statistics.
static constexpr size_t RequiredSize(size_t payload_size)
Compute the pool space consumed by a single allocation of payload_size bytes.
static constexpr size_t AlignSize(size_t raw_size)
Round a size up to the nearest multiple of the block alignment (8 bytes).
static const size_t BLOCK_ALIGN
Payload alignment and block size granularity in bytes.
STK_VIRT_DTOR ~BytePool()
Destructor.
static void AccountRun(size_t run, size_t &available, size_t &largest, size_t &fragments)
Add one free run of run bytes (headers included) to the statistics.
T * TimedAllocT(Timeout timeout_ticks=WAIT_INFINITE)
Allocate one typed block, blocking until memory becomes available or the timeout expires.
BytePool(uint8_t *storage, size_t storage_size, const char *name=nullptr)
Construct a pool backed by caller-supplied (external) storage.
bool m_storage_owned
true -> storage is heap-allocated; free in destructor
BlockHeader * m_first
first block header (aligned), nullptr if the pool is invalid
void * TryAlloc(size_t size)
Non-blocking allocation attempt.
void * TimedAlloc(size_t size, Timeout timeout_ticks=WAIT_INFINITE)
Allocate a block, blocking until memory becomes available or the timeout expires.
void Init()
Align the area and create the initial single free block.
void Coalesce(BlockHeader *h)
Merge h (a free block) with the free blocks that directly follow it.
Header preceding every block (free or used) inside the pool area.
uint32_t state
STATE_FREE / STATE_USED, anything else is treated as corruption.
uint32_t size
total block size including this header (multiple of BLOCK_ALIGN)
void SetTraceName(const char *name)
Set name.
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.