10#include <stk_config.h>
23#define _STK_POOL_TEST_TASKS_MAX 5
24#define _STK_POOL_TEST_TIMEOUT 1000
25#define _STK_POOL_TEST_SHORT_SLEEP 10
26#define _STK_POOL_TEST_LONG_SLEEP 100
27#define _STK_POOL_BLOCK_SIZE 32U
28#define _STK_POOL_CAPACITY 8U
30#define _STK_POOL_STACK_SIZE 128
33#define _STK_POOL_STACK_SIZE 256
34#define STK_TASK static
55alignas(
sizeof(
void *))
static uint8_t
68template <EAccessMode _AccessMode>
87 ok &= (
g_Pool->GetUsedCount() == 0U);
90 void *blk =
g_Pool->TryAlloc();
91 ok &= (blk !=
nullptr);
92 ok &= (
g_Pool->GetUsedCount() == 1U);
101 ok &= (
g_Pool->GetUsedCount() == 0U);
104 void *blk2 =
g_Pool->TryAlloc();
105 ok &= (blk2 !=
nullptr);
108 printf(
"TryAllocFree: %s\n", ok ?
"PASS" :
"FAIL");
125template <EAccessMode _AccessMode>
145 blocks[i] =
g_Pool->TryAlloc();
146 ok &= (blocks[i] !=
nullptr);
150 ok &= (
g_Pool->GetFreeCount() == 0U);
154 void *extra =
g_Pool->TryAlloc();
155 ok &= (extra ==
nullptr);
159 ok &=
g_Pool->Free(blocks[i]);
163 printf(
"ExhaustPool: %s\n", ok ?
"PASS" :
"FAIL");
180template <EAccessMode _AccessMode>
197 blocks[i] =
g_Pool->TryAlloc();
216 void *blk =
g_Pool->Alloc();
233 printf(
"BlockingAlloc: %s\n", ok ?
"PASS" :
"FAIL");
248template <EAccessMode _AccessMode>
265 blocks[i] =
g_Pool->TryAlloc();
279 void *blk =
g_Pool->TimedAlloc(50);
282 bool ok = (blk ==
nullptr) && (elapsed >= 45) && (elapsed <= 65);
285 printf(
"TimedAllocTimeout: blk=%s elapsed=%d %s\n",
286 blk ?
"non-null" :
"null", (
int)elapsed, ok ?
"PASS" :
"FAIL");
307template <EAccessMode _AccessMode>
323 blocks[i] =
g_Pool->TryAlloc();
340 void *blk =
g_Pool->TimedAlloc(150);
342 bool ok = (blk !=
nullptr);
345 if (blk)
g_Pool->Free(blk);
347 printf(
"TimedAllocSuccess: %s\n", ok ?
"PASS" :
"FAIL");
368template <EAccessMode _AccessMode>
385 int32_t *blk =
g_Pool->AllocT<int32_t>();
406 printf(
"ConcurrentAllocFree: counter=%d (expected %d) %s\n",
431template <EAccessMode _AccessMode>
449 ok &= (rec !=
nullptr);
453 rec->
value = 0xDEADBEEFU;
454 ok &= (rec->
id == 42U) && (rec->
value == 0xDEADBEEFU);
460 ok &= (rec2 !=
nullptr);
465 ok &= (rec2->
id == 7U);
471 ok &= (rec3 !=
nullptr);
472 if (rec3)
g_Pool->Free(rec3);
474 printf(
"TypedAlloc: %s\n", ok ?
"PASS" :
"FAIL");
490template <EAccessMode _AccessMode>
506 size_t free_before =
g_Pool->GetFreeCount();
509 bool result =
g_Pool->Free(
nullptr);
513 ok &= (
g_Pool->GetFreeCount() == free_before);
515 printf(
"FreeNull: %s\n", ok ?
"PASS" :
"FAIL");
532template <EAccessMode _AccessMode>
548 const size_t align =
sizeof(
void *);
551 size_t a1 = stk::memory::BlockMemoryPool::AlignBlockSize(1U);
553 ok &= (a1 % align == 0U);
556 size_t a2 = stk::memory::BlockMemoryPool::AlignBlockSize(align);
560 size_t a3 = stk::memory::BlockMemoryPool::AlignBlockSize(align + 1U);
561 ok &= (a3 == 2U * align);
564 size_t a4 = stk::memory::BlockMemoryPool::AlignBlockSize(3U * align);
565 ok &= (a4 == 3U * align);
568 size_t expected_block_size = stk::memory::BlockMemoryPool::AlignBlockSize(
_STK_POOL_BLOCK_SIZE);
569 ok &= (
g_Pool->GetBlockSize() == expected_block_size);
571 printf(
"AlignBlockSize: a1=%u a2=%u a3=%u a4=%u expected_bs=%u %s\n",
572 a1, a2, a3, a4, expected_block_size, ok ?
"PASS" :
"FAIL");
590template <EAccessMode _AccessMode>
607 ok &=
g_Pool->IsStorageValid();
611 const size_t heap_cap = 4U;
612 const size_t heap_bsz = 16U;
615 ok &= heap_pool.IsStorageValid();
616 ok &= (heap_pool.GetCapacity() == heap_cap);
617 ok &= (heap_pool.GetBlockSize() >= heap_bsz);
618 ok &= (heap_pool.GetBlockSize() %
sizeof(
void *) == 0U);
619 ok &= heap_pool.IsEmpty();
622 void *blk = heap_pool.TryAlloc();
623 ok &= (blk !=
nullptr);
624 ok &= (heap_pool.GetUsedCount() == 1U);
626 ok &= heap_pool.IsEmpty();
628 printf(
"StorageMode: %s\n", ok ?
"PASS" :
"FAIL");
645template <EAccessMode _AccessMode>
665 case 0: blk =
g_Pool->TryAlloc();
break;
666 case 1: blk =
g_Pool->Alloc();
break;
667 case 2: blk =
g_Pool->TimedAlloc(20);
break;
692 printf(
"Stress: counter=%d pool_empty=%s %s\n",
694 g_Pool->IsEmpty() ?
"yes" :
"no",
695 ok ?
"PASS" :
"FAIL");
728 return (strcmp(test_name,
"BlockingAlloc") == 0) ||
729 (strcmp(test_name,
"TimedAllocTimeout") == 0) ||
730 (strcmp(test_name,
"TimedAllocSuccess") == 0) ||
731 (strcmp(test_name,
"ConcurrentAllocFree")== 0) ||
732 (strcmp(test_name,
"Stress") == 0);
742 return (strcmp(test_name,
"ConcurrentAllocFree") == 0) ||
743 (strcmp(test_name,
"Stress") == 0);
753template <
class TaskType>
754static int32_t
RunTest(
const char *test_name, int32_t param = 0)
760 printf(
"Test: %s\n", test_name);
774 TaskType task2(2, param);
775 TaskType task3(3, param);
776 TaskType task4(4, param);
799 printf(
"--------------\n");
818 int total_failures = 0, total_success = 0;
820 printf(
"--------------\n");
824#define RUN(TestClass, name, param) \
826 if (RunTest<TestClass<ACCESS_PRIVILEGED>>(name, param) \
827 != TestContext::SUCCESS_EXIT_CODE) \
833#ifndef __ARM_ARCH_6M__
872 int32_t final_result = (total_failures == 0
876 printf(
"##############\n");
877 printf(
"Total tests: %d\n", total_failures + total_success);
878 printf(
"Failures: %d\n", (
int)total_failures);
Implementation of fixed-size block memory pool: stk::memory::BlockMemoryPool.
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
#define STK_TICKLESS_IDLE
Enables tickless (dynamic-tick) low-power operation during idle periods.
#define _STK_POOL_TEST_SHORT_SLEEP
static bool NeedsTwoTasks(const char *test_name)
int main(int argc, char **argv)
static bool NeedsAllTasks(const char *test_name)
static int32_t RunTest(const char *test_name, int32_t param=0)
#define _STK_POOL_BLOCK_SIZE
#define _STK_POOL_CAPACITY
#define _STK_POOL_TEST_TASKS_MAX
#define _STK_POOL_TEST_LONG_SLEEP
#define RUN(TestClass, name, param)
#define STK_TEST_DECL_ASSERT
Declare assertion redirector in the source file.
Namespace of STK package.
static int64_t GetTimeNowMs()
Get current time in milliseconds since kernel start.
void Sleep(Timeout ticks)
Put calling process into a sleep state.
void Yield()
Notify scheduler to switch to the next runnable task.
PlatformArmCortexM PlatformDefault
Default platform implementation.
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
void Delay(Timeout ticks)
Delay calling process by busy-waiting until the deadline expires.
SwitchStrategyRoundRobin SwitchStrategyRR
Shorthand alias for SwitchStrategyRoundRobin.
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
@ KERNEL_SYNC
Synchronization support (see Event).
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
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.
Namespace of the test inventory.
Namespace of BlockMemoryPool test.
static volatile int32_t g_InstancesDone
static void ResetTestState()
static Kernel< KERNEL_DYNAMIC|KERNEL_SYNC|(STK_TICKLESS_IDLE ? KERNEL_TICKLESS :0), 5, SwitchStrategyRR, PlatformDefault > g_Kernel
static volatile int32_t g_SharedCounter
static stk::memory::BlockMemoryPool * g_Pool
static volatile int32_t g_TestResult
static uint8_t g_PoolStorage[8U *stk::memory::BlockMemoryPool::AlignBlockSize(32U)]
Concrete implementation of IKernel.
Task(const Task &)=delete
Verifies TryAlloc returns a valid block, Free recycles it, and pool accounting stays consistent throu...
void Run() override
Entry point of the user task.
TryAllocFreeTask(uint8_t task_id, int32_t)
Drains the entire pool via TryAlloc, verifies IsFull() and that a further TryAlloc returns nullptr,...
void Run() override
Entry point of the user task.
ExhaustPoolTask(uint8_t task_id, int32_t)
Task 0 holds all blocks; Task 1 blocks in Alloc(); Task 0 frees one block and verifies Task 1 unblock...
BlockingAllocTask(uint8_t task_id, int32_t)
void Run() override
Entry point of the user task.
Task 0 holds all blocks; Task 1 calls TimedAlloc with a short timeout that must expire,...
TimedAllocTimeoutTask(uint8_t task_id, int32_t)
void Run() override
Entry point of the user task.
Task 0 holds all blocks; Task 1 calls TimedAlloc with a generous timeout; Task 0 frees a block before...
void Run() override
Entry point of the user task.
TimedAllocSuccessTask(uint8_t task_id, int32_t)
All tasks race to alloc a block, increment a shared counter inside the block, copy it out and free; t...
ConcurrentAllocFreeTask(uint8_t task_id, int32_t iterations)
void Run() override
Entry point of the user task.
Verifies that the typed wrappers AllocT<T>(), TryAllocT<T>(), and TimedAllocT<T>() return correctly t...
void Run() override
Entry point of the user task.
TypedAllocTask(uint8_t task_id, int32_t)
Ensures Free(nullptr) returns false and does not corrupt the pool.
FreeNullTask(uint8_t task_id, int32_t)
void Run() override
Entry point of the user task.
Verifies AlignBlockSize() rounds up to BLOCK_ALIGN multiples and never returns a value smaller than B...
AlignBlockSizeTask(uint8_t task_id, int32_t)
void Run() override
Entry point of the user task.
Creates a second pool using heap storage and verifies accessors report correct values for both storag...
StorageModeTask(uint8_t task_id, int32_t)
void Run() override
Entry point of the user task.
All tasks hammer the pool with a mix of TryAlloc, blocking Alloc, and TimedAlloc operations; verifies...
StressTask(uint8_t task_id, int32_t iterations)
void Run() override
Entry point of the user task.
static void ShowTestSuitePrologue()
Show text string as prologue before tests start.
@ DEFAULT_FAILURE_EXIT_CODE
default exit code for exit() to denote failure of the test
@ SUCCESS_EXIT_CODE
exit code for exit() to denote the success of the test
static void ShowTestSuiteEpilogue(int32_t result)
Show text string as epilogue after tests end.