summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorTangyuxin <[email protected]>2021-12-16 16:23:58 +0800
committerGitHub <[email protected]>2021-12-16 16:23:58 +0800
commitd724eed9fc09269c3c6e921c1f8b2df573508419 (patch)
tree92f8528e0efbe28d4632692896d0bcaa2e45b3b6 /examples
parent874f6c84f19f8ca24ebd00a9a95e7af02afc49a0 (diff)
分离内存分配接口与内存分配算法 (#5175)
* [kernel][mem] Multiple instances of small memory allocation algorithm * [kernel][mem] Change small memory management algorithm memory header flag * [kernel][mem] Fix assertion problem * [kernel][slab] Multiple instances of slab memory management algorithm * [kernel][memheap] Remove rt_malloc/rt_free/rt_realloc and other related memory interfaces * [kernel][mem] Clean up memory space of small memory management objects * [kernel][kservice] Add memory application interface and thread protection interface * [kernel][kservice] Fix function return value problem * [kernel][memheap] Optimize memheaptrace print * [kernel][memheap] Support best mode * [kernel][memory] Remove semaphore lock * [kernel][memheap] Add locked flag * [kernel][memory] Support malloc memory in interrupt * [kernel][memheap] Add 'memheapcheck' cmd * [kernel][mem] Fix failure to request full memory * [kernel][memheap] Fix compilation warning * [kernel][mem] Fix mem realloc ASSERT * [examples][testcases] Add small mem testcase * [examples][mem_tc] Modify test memory size * [examples][testcases] Add slab memory management algorithm test case * [examples][testcases] fix small memory management algorithm test case * [kernel][memory] Adjusting memory allocation algorithm object definition and interface * [kernel][memory] Fix compilation warning * [examples][utest] Fix mem test case * [examples][utest] fix slab test case * [utest][testcases] Shorten test time * [kernel][memory] Formatting code * [examples][utest] Adjust test run time * [examples][utest] Formatting code * [bsp] update all rtconfig.h
Diffstat (limited to 'examples')
-rw-r--r--examples/utest/testcases/kernel/Kconfig10
-rw-r--r--examples/utest/testcases/kernel/SConscript6
-rw-r--r--examples/utest/testcases/kernel/mem_tc.c588
-rw-r--r--examples/utest/testcases/kernel/slab_tc.c323
4 files changed, 927 insertions, 0 deletions
diff --git a/examples/utest/testcases/kernel/Kconfig b/examples/utest/testcases/kernel/Kconfig
index 08c3022b77..0faa3622fb 100644
--- a/examples/utest/testcases/kernel/Kconfig
+++ b/examples/utest/testcases/kernel/Kconfig
@@ -5,6 +5,16 @@ config UTEST_MEMHEAP_TC
default y
depends on RT_USING_MEMHEAP
+config UTEST_SMALL_MEM_TC
+ bool "mem test"
+ default y
+ depends on RT_USING_SMALL_MEM
+
+config UTEST_SLAB_TC
+ bool "slab test"
+ default n
+ depends on RT_USING_SLAB
+
config UTEST_IRQ_TC
bool "IRQ test"
default n
diff --git a/examples/utest/testcases/kernel/SConscript b/examples/utest/testcases/kernel/SConscript
index 0d2645427b..ab98c6065b 100644
--- a/examples/utest/testcases/kernel/SConscript
+++ b/examples/utest/testcases/kernel/SConscript
@@ -8,6 +8,12 @@ src = Split('''
if GetDepend(['UTEST_MEMHEAP_TC']):
src += ['memheap_tc.c']
+if GetDepend(['UTEST_SMALL_MEM_TC']):
+ src += ['mem_tc.c']
+
+if GetDepend(['UTEST_SLAB_TC']):
+ src += ['slab_tc.c']
+
if GetDepend(['UTEST_IRQ_TC']):
src += ['irq_tc.c']
diff --git a/examples/utest/testcases/kernel/mem_tc.c b/examples/utest/testcases/kernel/mem_tc.c
new file mode 100644
index 0000000000..028876dfa9
--- /dev/null
+++ b/examples/utest/testcases/kernel/mem_tc.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-14 tyx the first version
+ */
+
+#include <rtthread.h>
+#include <stdlib.h>
+#include "utest.h"
+
+struct rt_small_mem_item
+{
+ rt_ubase_t pool_ptr; /**< small memory object addr */
+#ifdef ARCH_CPU_64BIT
+ rt_uint32_t resv;
+#endif /* ARCH_CPU_64BIT */
+ rt_size_t next; /**< next free item */
+ rt_size_t prev; /**< prev free item */
+#ifdef RT_USING_MEMTRACE
+#ifdef ARCH_CPU_64BIT
+ rt_uint8_t thread[8]; /**< thread name */
+#else
+ rt_uint8_t thread[4]; /**< thread name */
+#endif /* ARCH_CPU_64BIT */
+#endif /* RT_USING_MEMTRACE */
+};
+
+struct rt_small_mem
+{
+ struct rt_memory parent; /**< inherit from rt_memory */
+ rt_uint8_t *heap_ptr; /**< pointer to the heap */
+ struct rt_small_mem_item *heap_end;
+ struct rt_small_mem_item *lfree;
+ rt_size_t mem_size_aligned; /**< aligned memory size */
+};
+
+#define MEM_SIZE(_heap, _mem) \
+ (((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \
+ (rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE))
+
+#define TEST_MEM_SIZE 1024
+
+static rt_size_t max_block(struct rt_small_mem *heap)
+{
+ struct rt_small_mem_item *mem;
+ rt_size_t max = 0, size;
+
+ for (mem = (struct rt_small_mem_item *)heap->heap_ptr;
+ mem != heap->heap_end;
+ mem = (struct rt_small_mem_item *)&heap->heap_ptr[mem->next])
+ {
+ if (((rt_ubase_t)mem->pool_ptr & 0x1) == 0)
+ {
+ size = MEM_SIZE(heap, mem);
+ if (size > max)
+ {
+ max = size;
+ }
+ }
+ }
+ return max;
+}
+
+static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
+{
+ while (size-- != 0)
+ {
+ if (*(rt_uint8_t *)ptr != v)
+ return *(rt_uint8_t *)ptr - v;
+ }
+ return 0;
+}
+
+struct mem_test_context
+{
+ void *ptr;
+ rt_size_t size;
+ rt_uint8_t magic;
+};
+
+static void mem_functional_test(void)
+{
+ rt_size_t total_size;
+ rt_uint8_t *buf;
+ struct rt_small_mem *heap;
+ rt_uint8_t magic = __LINE__;
+
+ /* Prepare test memory */
+ buf = rt_malloc(TEST_MEM_SIZE);
+ uassert_not_null(buf);
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
+ rt_memset(buf, 0xAA, TEST_MEM_SIZE);
+ /* small heap init */
+ heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
+ /* get total size */
+ total_size = max_block(heap);
+ uassert_int_not_equal(total_size, 0);
+ /*
+ * Allocate all memory at a time and test whether
+ * the memory allocation release function is effective
+ */
+ {
+ struct mem_test_context ctx;
+ ctx.magic = magic++;
+ ctx.size = max_block(heap);
+ ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
+ uassert_not_null(ctx.ptr);
+ rt_memset(ctx.ptr, ctx.magic, ctx.size);
+ uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
+ rt_smem_free(ctx.ptr);
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /*
+ * Apply for memory release sequentially and
+ * test whether memory block merging is effective
+ */
+ {
+ rt_size_t i, max_free = 0;
+ struct mem_test_context ctx[3];
+ /* alloc mem */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ ctx[i].magic = magic++;
+ ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
+ ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
+ uassert_not_null(ctx[i].ptr);
+ rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
+ }
+ /* All memory has been applied. The remaining memory should be 0 */
+ uassert_int_equal(max_block(heap), 0);
+ /* Verify that the memory data is correct */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
+ }
+ /* Sequential memory release */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
+ rt_smem_free(ctx[i].ptr);
+ max_free += ctx[i].size;
+ uassert_true(max_block(heap) >= max_free);
+ }
+ /* Check whether the memory is fully merged */
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /*
+ * Apply for memory release at an interval to
+ * test whether memory block merging is effective
+ */
+ {
+ rt_size_t i, max_free = 0;
+ struct mem_test_context ctx[3];
+ /* alloc mem */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ ctx[i].magic = magic++;
+ ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
+ ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
+ uassert_not_null(ctx[i].ptr);
+ rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
+ }
+ /* All memory has been applied. The remaining memory should be 0 */
+ uassert_int_equal(max_block(heap), 0);
+ /* Verify that the memory data is correct */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
+ }
+ /* Release even address */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ if (i % 2 == 0)
+ {
+ uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
+ rt_smem_free(ctx[i].ptr);
+ uassert_true(max_block(heap) >= ctx[0].size);
+ }
+ }
+ /* Release odd addresses and merge memory blocks */
+ for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
+ {
+ if (i % 2 != 0)
+ {
+ uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
+ rt_smem_free(ctx[i].ptr);
+ max_free += ctx[i - 1].size + ctx[i + 1].size;
+ uassert_true(max_block(heap) >= max_free);
+ }
+ }
+ /* Check whether the memory is fully merged */
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /* mem realloc test,Small - > Large */
+ {
+ /* Request a piece of memory for subsequent reallocation operations */
+ struct mem_test_context ctx[3];
+ ctx[0].magic = magic++;
+ ctx[0].size = max_block(heap) / 3;
+ ctx[0].ptr = rt_smem_alloc(&heap->parent, ctx[0].size);
+ uassert_not_null(ctx[0].ptr);
+ rt_memset(ctx[0].ptr, ctx[0].magic, ctx[0].size);
+ /* Apply for a small piece of memory and split the continuous memory */
+ ctx[1].magic = magic++;
+ ctx[1].size = RT_ALIGN_SIZE;
+ ctx[1].ptr = rt_smem_alloc(&heap->parent, ctx[1].size);
+ uassert_not_null(ctx[1].ptr);
+ rt_memset(ctx[1].ptr, ctx[1].magic, ctx[1].size);
+ /* Check whether the maximum memory block is larger than the first piece of memory */
+ uassert_true(max_block(heap) > ctx[0].size);
+ /* Reallocate the first piece of memory */
+ ctx[2].magic = magic++;
+ ctx[2].size = max_block(heap);
+ ctx[2].ptr = rt_smem_realloc(&heap->parent, ctx[0].ptr, ctx[2].size);
+ uassert_not_null(ctx[2].ptr);
+ uassert_int_not_equal(ctx[0].ptr, ctx[2].ptr);
+ uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[0].magic, ctx[0].size), 0);
+ rt_memset(ctx[2].ptr, ctx[2].magic, ctx[2].size);
+ /* Free the second piece of memory */
+ uassert_int_equal(_mem_cmp(ctx[1].ptr, ctx[1].magic, ctx[1].size), 0);
+ rt_smem_free(ctx[1].ptr);
+ /* Free reallocated memory */
+ uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[2].magic, ctx[2].size), 0);
+ rt_smem_free(ctx[2].ptr);
+ /* Check memory integrity */
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /* mem realloc test,Large - > Small */
+ {
+ rt_size_t max_free;
+ struct mem_test_context ctx;
+ /* alloc a piece of memory */
+ ctx.magic = magic++;
+ ctx.size = max_block(heap) / 2;
+ ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
+ uassert_not_null(ctx.ptr);
+ rt_memset(ctx.ptr, ctx.magic, ctx.size);
+ uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
+ /* Get remaining memory */
+ max_free = max_block(heap);
+ /* Change memory size */
+ ctx.size = ctx.size / 2;
+ uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
+ /* Get remaining size */
+ uassert_true(max_block(heap) > max_free);
+ /* Free memory */
+ uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
+ rt_smem_free(ctx.ptr);
+ /* Check memory integrity */
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /* mem realloc test,equal */
+ {
+ rt_size_t max_free;
+ struct mem_test_context ctx;
+ /* alloc a piece of memory */
+ ctx.magic = magic++;
+ ctx.size = max_block(heap) / 2;
+ ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
+ uassert_not_null(ctx.ptr);
+ rt_memset(ctx.ptr, ctx.magic, ctx.size);
+ uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
+ /* Get remaining memory */
+ max_free = max_block(heap);
+ /* Do not change memory size */
+ uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
+ /* Get remaining size */
+ uassert_true(max_block(heap) == max_free);
+ /* Free memory */
+ uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
+ rt_smem_free(ctx.ptr);
+ /* Check memory integrity */
+ uassert_int_equal(max_block(heap), total_size);
+ }
+ /* small heap deinit */
+ rt_smem_detach(&heap->parent);
+ /* release test resources */
+ rt_free(buf);
+}
+
+struct mem_alloc_context
+{
+ rt_list_t node;
+ rt_size_t size;
+ rt_uint8_t magic;
+};
+
+struct mem_alloc_head
+{
+ rt_list_t list;
+ rt_size_t count;
+ rt_tick_t start;
+ rt_tick_t end;
+ rt_tick_t interval;
+};
+
+#define MEM_RANG_ALLOC_BLK_MIN 2
+#define MEM_RANG_ALLOC_BLK_MAX 5
+#define MEM_RANG_ALLOC_TEST_TIME 5
+
+static void mem_alloc_test(void)
+{
+ struct mem_alloc_head head;
+ rt_uint8_t *buf;
+ struct rt_small_mem *heap;
+ rt_size_t total_size, size;
+ struct mem_alloc_context *ctx;
+
+ /* init */
+ rt_list_init(&head.list);
+ head.count = 0;
+ head.start = rt_tick_get();
+ head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
+ head.interval = (head.end - head.start) / 20;
+ buf = rt_malloc(TEST_MEM_SIZE);
+ uassert_not_null(buf);
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
+ rt_memset(buf, 0xAA, TEST_MEM_SIZE);
+ heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
+ total_size = max_block(heap);
+ uassert_int_not_equal(total_size, 0);
+ /* test run */
+ while (head.end - head.start < RT_TICK_MAX / 2)
+ {
+ if (rt_tick_get() - head.start >= head.interval)
+ {
+ head.start = rt_tick_get();
+ rt_kprintf("#");
+ }
+ /* %60 probability to perform alloc operation */
+ if (rand() % 10 >= 4)
+ {
+ size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
+ size *= sizeof(struct mem_alloc_context);
+ ctx = rt_smem_alloc(&heap->parent, size);
+ if (ctx == RT_NULL)
+ {
+ if (head.count == 0)
+ {
+ break;
+ }
+ size = head.count / 2;
+ while (size != head.count)
+ {
+ ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_smem_free(ctx);
+ head.count --;
+ }
+ continue;
+ }
+ if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
+ {
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
+ }
+ rt_memset(ctx, 0, size);
+ rt_list_init(&ctx->node);
+ ctx->size = size;
+ ctx->magic = rand() & 0xff;
+ if (ctx->size > sizeof(*ctx))
+ {
+ rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ rt_list_insert_after(&head.list, &ctx->node);
+ head.count += 1;
+ }
+ else
+ {
+ if (!rt_list_isempty(&head.list))
+ {
+ ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_smem_free(ctx);
+ head.count --;
+ }
+ }
+ }
+ while (!rt_list_isempty(&head.list))
+ {
+ ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_smem_free(ctx);
+ head.count --;
+ }
+ uassert_int_equal(head.count, 0);
+ uassert_int_equal(max_block(heap), total_size);
+ /* small heap deinit */
+ rt_smem_detach(&heap->parent);
+ /* release test resources */
+ rt_free(buf);
+}
+
+#define MEM_RANG_REALLOC_BLK_MIN 0
+#define MEM_RANG_REALLOC_BLK_MAX 5
+#define MEM_RANG_REALLOC_TEST_TIME 5
+
+struct mem_realloc_context
+{
+ rt_size_t size;
+ rt_uint8_t magic;
+};
+
+struct mem_realloc_head
+{
+ struct mem_realloc_context **ctx_tab;
+ rt_size_t count;
+ rt_tick_t start;
+ rt_tick_t end;
+ rt_tick_t interval;
+};
+
+static void mem_realloc_test(void)
+{
+ struct mem_realloc_head head;
+ rt_uint8_t *buf;
+ struct rt_small_mem *heap;
+ rt_size_t total_size, size, idx;
+ struct mem_realloc_context *ctx;
+ int res;
+
+ size = RT_ALIGN(sizeof(struct mem_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
+ size = TEST_MEM_SIZE / size;
+ /* init */
+ head.ctx_tab = RT_NULL;
+ head.count = size;
+ head.start = rt_tick_get();
+ head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
+ head.interval = (head.end - head.start) / 20;
+ buf = rt_malloc(TEST_MEM_SIZE);
+ uassert_not_null(buf);
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
+ rt_memset(buf, 0xAA, TEST_MEM_SIZE);
+ heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
+ total_size = max_block(heap);
+ uassert_int_not_equal(total_size, 0);
+ /* init ctx tab */
+ size = head.count * sizeof(struct mem_realloc_context *);
+ head.ctx_tab = rt_smem_alloc(&heap->parent, size);
+ uassert_not_null(head.ctx_tab);
+ rt_memset(head.ctx_tab, 0, size);
+ /* test run */
+ while (head.end - head.start < RT_TICK_MAX / 2)
+ {
+ if (rt_tick_get() - head.start >= head.interval)
+ {
+ head.start = rt_tick_get();
+ rt_kprintf("#");
+ }
+ size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
+ size *= sizeof(struct mem_realloc_context);
+ idx = rand() % head.count;
+ ctx = rt_smem_realloc(&heap->parent, head.ctx_tab[idx], size);
+ if (ctx == RT_NULL)
+ {
+ if (size == 0)
+ {
+ if (head.ctx_tab[idx])
+ {
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < head.count; idx++)
+ {
+ ctx = head.ctx_tab[idx];
+ if (rand() % 2 && ctx)
+ {
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_smem_realloc(&heap->parent, ctx, 0);
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ }
+ }
+ continue;
+ }
+ /* check mem */
+ if (head.ctx_tab[idx] != RT_NULL)
+ {
+ res = 0;
+ if (ctx->size < size)
+ {
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ }
+ else
+ {
+ if (size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
+ }
+ }
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ /* init mem */
+ ctx->magic = rand() & 0xff;
+ ctx->size = size;
+ if (ctx->size > sizeof(*ctx))
+ {
+ rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ head.ctx_tab[idx] = ctx;
+ }
+ /* free all mem */
+ for (idx = 0; idx < head.count; idx++)
+ {
+ ctx = head.ctx_tab[idx];
+ if (ctx == RT_NULL)
+ {
+ continue;
+ }
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_smem_realloc(&heap->parent, ctx, 0);
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ uassert_int_not_equal(max_block(heap), total_size);
+ /* small heap deinit */
+ rt_smem_detach(&heap->parent);
+ /* release test resources */
+ rt_free(buf);
+}
+
+static rt_err_t utest_tc_init(void)
+{
+ return RT_EOK;
+}
+
+static rt_err_t utest_tc_cleanup(void)
+{
+ return RT_EOK;
+}
+
+static void testcase(void)
+{
+ UTEST_UNIT_RUN(mem_functional_test);
+ UTEST_UNIT_RUN(mem_alloc_test);
+ UTEST_UNIT_RUN(mem_realloc_test);
+}
+UTEST_TC_EXPORT(testcase, "testcases.kernel.mem_tc", utest_tc_init, utest_tc_cleanup, 20);
diff --git a/examples/utest/testcases/kernel/slab_tc.c b/examples/utest/testcases/kernel/slab_tc.c
new file mode 100644
index 0000000000..b273870cca
--- /dev/null
+++ b/examples/utest/testcases/kernel/slab_tc.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-14 tyx the first version
+ */
+
+#include <rtthread.h>
+#include <stdlib.h>
+#include "utest.h"
+
+#define TEST_SLAB_SIZE 1024 * 1024
+
+static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
+{
+ while (size-- != 0)
+ {
+ if (*(rt_uint8_t *)ptr != v)
+ return *(rt_uint8_t *)ptr - v;
+ }
+ return 0;
+}
+
+struct slab_alloc_context
+{
+ rt_list_t node;
+ rt_size_t size;
+ rt_uint8_t magic;
+};
+
+struct slab_alloc_head
+{
+ rt_list_t list;
+ rt_size_t count;
+ rt_tick_t start;
+ rt_tick_t end;
+ rt_tick_t interval;
+};
+
+#define SLAB_RANG_ALLOC_BLK_MIN 2
+#define SLAB_RANG_ALLOC_BLK_MAX 5
+#define SLAB_RANG_ALLOC_TEST_TIME 5
+
+static void slab_alloc_test(void)
+{
+ struct slab_alloc_head head;
+ rt_uint8_t *buf;
+ rt_slab_t heap;
+ rt_size_t size;
+ struct slab_alloc_context *ctx;
+
+ /* init */
+ rt_list_init(&head.list);
+ head.count = 0;
+ head.start = rt_tick_get();
+ head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000);
+ head.interval = (head.end - head.start) / 20;
+ buf = rt_malloc(TEST_SLAB_SIZE);
+ uassert_not_null(buf);
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
+ rt_memset(buf, 0xAA, TEST_SLAB_SIZE);
+ heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE);
+ // test run
+ while (head.end - head.start < RT_TICK_MAX / 2)
+ {
+ if (rt_tick_get() - head.start >= head.interval)
+ {
+ head.start = rt_tick_get();
+ rt_kprintf("#");
+ }
+ // %60 probability to perform alloc operation
+ if (rand() % 10 >= 4)
+ {
+ size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
+ size *= sizeof(struct slab_alloc_context);
+ ctx = rt_slab_alloc(heap, size);
+ if (ctx == RT_NULL)
+ {
+ if (head.count == 0)
+ {
+ break;
+ }
+ size = head.count / 2;
+ while (size != head.count)
+ {
+ ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_slab_free(heap, ctx);
+ head.count --;
+ }
+ continue;
+ }
+ //if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
+ //{
+ // uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
+ //}
+ rt_memset(ctx, 0, size);
+ rt_list_init(&ctx->node);
+ ctx->size = size;
+ ctx->magic = rand() & 0xff;
+ if (ctx->size > sizeof(*ctx))
+ {
+ rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ rt_list_insert_after(&head.list, &ctx->node);
+ head.count += 1;
+ }
+ else
+ {
+ if (!rt_list_isempty(&head.list))
+ {
+ ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_slab_free(heap, ctx);
+ head.count --;
+ }
+ }
+ }
+ while (!rt_list_isempty(&head.list))
+ {
+ ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
+ rt_list_remove(&ctx->node);
+ if (ctx->size > sizeof(*ctx))
+ {
+ if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
+ {
+ uassert_true(0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_slab_free(heap, ctx);
+ head.count --;
+ }
+ uassert_int_equal(head.count, 0);
+ // slab heap deinit
+ rt_slab_detach(heap);
+ /* release test resources */
+ rt_free(buf);
+}
+
+#define SLAB_RANG_REALLOC_BLK_MIN 0
+#define SLAB_RANG_REALLOC_BLK_MAX 5
+#define SLAB_RANG_REALLOC_TEST_TIME 5
+
+struct slab_realloc_context
+{
+ rt_size_t size;
+ rt_uint8_t magic;
+};
+
+struct slab_realloc_head
+{
+ struct slab_realloc_context **ctx_tab;
+ rt_size_t count;
+ rt_tick_t start;
+ rt_tick_t end;
+ rt_tick_t interval;
+};
+
+static void slab_realloc_test(void)
+{
+ struct slab_realloc_head head;
+ rt_uint8_t *buf;
+ rt_slab_t heap;
+ rt_size_t size, idx;
+ struct slab_realloc_context *ctx;
+ int res;
+
+ size = RT_ALIGN(sizeof(struct slab_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
+ size = TEST_SLAB_SIZE / size;
+ /* init */
+ head.ctx_tab = RT_NULL;
+ head.count = size;
+ head.start = rt_tick_get();
+ head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000);
+ head.interval = (head.end - head.start) / 20;
+ buf = rt_malloc(TEST_SLAB_SIZE);
+ uassert_not_null(buf);
+ uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
+ rt_memset(buf, 0xAA, TEST_SLAB_SIZE);
+ heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE);
+ /* init ctx tab */
+ size = head.count * sizeof(struct slab_realloc_context *);
+ head.ctx_tab = rt_slab_alloc(heap, size);
+ uassert_not_null(head.ctx_tab);
+ rt_memset(head.ctx_tab, 0, size);
+ // test run
+ while (head.end - head.start < RT_TICK_MAX / 2)
+ {
+ if (rt_tick_get() - head.start >= head.interval)
+ {
+ head.start = rt_tick_get();
+ rt_kprintf("#");
+ }
+ size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
+ size *= sizeof(struct slab_realloc_context);
+ idx = rand() % head.count;
+ ctx = rt_slab_realloc(heap, head.ctx_tab[idx], size);
+ if (ctx == RT_NULL)
+ {
+ if (size == 0)
+ {
+ if (head.ctx_tab[idx])
+ {
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < head.count; idx++)
+ {
+ ctx = head.ctx_tab[idx];
+ if (rand() % 2 && ctx)
+ {
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_slab_realloc(heap, ctx, 0);
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ }
+ }
+ continue;
+ }
+ /* check slab */
+ if (head.ctx_tab[idx] != RT_NULL)
+ {
+ res = 0;
+ if (ctx->size < size)
+ {
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ }
+ else
+ {
+ if (size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
+ }
+ }
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ /* init slab */
+ ctx->magic = rand() & 0xff;
+ ctx->size = size;
+ if (ctx->size > sizeof(*ctx))
+ {
+ rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ }
+ head.ctx_tab[idx] = ctx;
+ }
+ // free all slab
+ for (idx = 0; idx < head.count; idx++)
+ {
+ ctx = head.ctx_tab[idx];
+ if (ctx == RT_NULL)
+ {
+ continue;
+ }
+ if (ctx->size > sizeof(*ctx))
+ {
+ res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
+ if (res != 0)
+ {
+ uassert_int_equal(res, 0);
+ }
+ }
+ rt_memset(ctx, 0xAA, ctx->size);
+ rt_slab_realloc(heap, ctx, 0);
+ head.ctx_tab[idx] = RT_NULL;
+ }
+ // slab heap deinit
+ rt_slab_detach(heap);
+ /* release test resources */
+ rt_free(buf);
+}
+
+static rt_err_t utest_tc_init(void)
+{
+ return RT_EOK;
+}
+
+static rt_err_t utest_tc_cleanup(void)
+{
+ return RT_EOK;
+}
+
+static void testcase(void)
+{
+ UTEST_UNIT_RUN(slab_alloc_test);
+ UTEST_UNIT_RUN(slab_realloc_test);
+}
+UTEST_TC_EXPORT(testcase, "testcases.kernel.slab_tc", utest_tc_init, utest_tc_cleanup, 20);