From bec68c37132f62fdd565b801c0f811b9fbfcfe12 Mon Sep 17 00:00:00 2001 From: lixianjing Date: Thu, 22 Apr 2021 14:52:29 +0800 Subject: [PATCH] memory manager support multi blocks of memory --- awtk_config.py | 5 +- docs/README.md | 1 + docs/changes.md | 4 + docs/how_to_support_multi_mem_block.md | 41 +++++ src/base/awtk_config_sample.h | 6 + src/platforms/pc/platform.c | 9 +- src/tkc/mem.c | 28 +-- src/tkc/mem.h | 18 ++ src/tkc/mem_allocator_composite.h | 226 +++++++++++++++++++++++++ src/tkc/mem_allocator_simple.h | 27 ++- tests/SConscript | 1 - tests/allocator_test.c | 123 ++++++++++++-- 12 files changed, 453 insertions(+), 36 deletions(-) create mode 100644 docs/how_to_support_multi_mem_block.md create mode 100644 src/tkc/mem_allocator_composite.h diff --git a/awtk_config.py b/awtk_config.py index 055487bff..da19eb7f6 100644 --- a/awtk_config.py +++ b/awtk_config.py @@ -93,7 +93,10 @@ COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_EVENT_RECORDER_PLAYER=1 ' COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_ASSET_LOADER -DWITH_FS_RES -DWITH_ASSET_LOADER_ZIP ' COMMON_CCFLAGS=COMMON_CCFLAGS+' -DSTBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE ' COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_VGCANVAS -DWITH_UNICODE_BREAK -DWITH_DESKTOP_STYLE ' -COMMON_CCFLAGS=COMMON_CCFLAGS+' -DHAS_STD_MALLOC -DWITH_SDL -DHAS_STDIO -DHAVE_STDIO_H -DHAS_GET_TIME_US64 ' +COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_SDL -DHAS_STDIO -DHAVE_STDIO_H -DHAS_GET_TIME_US64 ' +COMMON_CCFLAGS=COMMON_CCFLAGS+' -DHAS_STD_MALLOC -DTK_MAX_MEM_BLOCK_NR=3 ' + +#COMMON_CCFLAGS=COMMON_CCFLAGS+' -DTK_MAX_MEM_BLOCK_NR=3 ' GRAPHIC_BUFFER='default' diff --git a/docs/README.md b/docs/README.md index 130f9cbc4..129d2aa28 100644 --- a/docs/README.md +++ b/docs/README.md @@ -87,6 +87,7 @@ * [如何使用 packed 图](how_to_use_packed_image.md) * [如何根据实际分辨率自动调整窗口中子控件的位置大小](how_to_auto_scale_children.md) * [如何修改 stb\_truetype 获取字模时申请的缓冲区大小](how_to_modify_stb_truetype_buffer_size.md) +* [如何让内存管理器支持管理多块不连续的内存](how_to_support_multi_mem_block.md) ### 3. 内部原理 * [AWTK 脚本绑定原理](script_binding.md) diff --git a/docs/changes.md b/docs/changes.md index 7a2964644..98d3fa8fd 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,9 @@ # 最新动态 +2021/04/22 + * 修改内存泄漏问题。 + * 内存管理器支持管理多块不连续的内存。 + 2021/04/20 * 完善progress cirle demo(感谢雨欣提供补丁) * 添加 获取光标位置 接口(感谢兆坤提供补丁) diff --git a/docs/how_to_support_multi_mem_block.md b/docs/how_to_support_multi_mem_block.md new file mode 100644 index 000000000..1b07d03f1 --- /dev/null +++ b/docs/how_to_support_multi_mem_block.md @@ -0,0 +1,41 @@ +# AWTK 内存分配器支持多块不连续的内存。 + +在嵌入式系统中,可能有多块不连续的内存。AWTK 最新版本支持管理多个不连续的内存块。使用方法如下: + +* 定义内存块数目 + +> 在 awtk\_config.h 中定义: + +```c +#define TK_MAX_MEM_BLOCK_NR 3 +``` + +* 初始化内存 + +> 需要使用 tk\_mem\_init\_ex 代替 tk\_mem\_init 初始化内存。一般将大块放到前面,小块放到后面。也可以将速度快的内存放到前面,将速度慢的放到后面。 + +```c +/** + * @method tk_mem_init_ex + * @export none + * 初始化内存,支持多块不连续的内存。 + * >最后一个参数必须为NULL。 + * + * 示例: + * ```c + * tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL); + * ``` + * + * @param {void*} buffer 内存地址。 + * @param {uint32_t} size 内存长度。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...); + +``` + +示例: +```c + tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL); +``` diff --git a/src/base/awtk_config_sample.h b/src/base/awtk_config_sample.h index b55881cfb..d8adc7a5f 100644 --- a/src/base/awtk_config_sample.h +++ b/src/base/awtk_config_sample.h @@ -235,4 +235,10 @@ * #define WITH_LCD_CLEAR_ALPHA 1 */ +/** + * 如果支持多块不连续的内存块,请定义内存块的数目。 + * + * #define TK_MAX_MEM_BLOCK_NR 4 + */ + #endif /*AWTK_CONFIG_H*/ diff --git a/src/platforms/pc/platform.c b/src/platforms/pc/platform.c index 12aee7d4b..960113094 100644 --- a/src/platforms/pc/platform.c +++ b/src/platforms/pc/platform.c @@ -193,15 +193,14 @@ void sleep_ms(uint32_t ms) { #endif } -#ifndef HAS_STD_MALLOC -static uint32_t s_heap_mem[3 * 1024 * 1024]; -#endif /*HAS_STD_MALLOC*/ - ret_t platform_prepare(void) { stm_time_init(); #ifndef HAS_STD_MALLOC - tk_mem_init(s_heap_mem, sizeof(s_heap_mem)); +static uint32_t s_heap_mem1[10 * 1024]; +static uint32_t s_heap_mem2[1 * 1024 * 1024]; +static uint32_t s_heap_mem3[3 * 1024 * 1024]; + tk_mem_init_ex(s_heap_mem1, sizeof(s_heap_mem1), s_heap_mem2, sizeof(s_heap_mem2), s_heap_mem3, sizeof(s_heap_mem3),NULL); #endif /*HAS_STD_MALLOC*/ date_time_global_init_ex(&s_date_time_vtable); diff --git a/src/tkc/mem.c b/src/tkc/mem.c index 9b09c4fea..0a38397c2 100644 --- a/src/tkc/mem.c +++ b/src/tkc/mem.c @@ -19,6 +19,7 @@ * */ +#include #include "tkc/mem.h" #include "tkc/time_now.h" #include "tkc/mem_allocator_oom.h" @@ -69,28 +70,25 @@ ret_t tk_mem_init_stage2(void) { #else /*non std memory manager*/ #include "tkc/mem_allocator_lock.h" -#include "tkc/mem_allocator_simple.h" +#include "tkc/mem_allocator_composite.h" static mem_allocator_lock_t s_lock; -static void* s_heap_start = NULL; -static uint32_t s_heap_size = 0; +static mem_allocator_pool_t pool; +static mem_allocator_composite_t composite; bool_t tk_mem_is_valid_addr(void* addr) { - uint64_t start = (uint64_t)s_heap_start; - uint64_t end = start + s_heap_size; - - return (((uint64_t)addr >= (uint64_t)start) && ((uint64_t)addr < end)); + return mem_allocator_composite_is_valid_addr(MEM_ALLOCATOR(&composite), addr); } -ret_t tk_mem_init(void* buffer, uint32_t size) { - static mem_allocator_simple_t simple; - static mem_allocator_pool_t pool; +ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...) { + va_list va; + va_start(va, size); + s_allocator = mem_allocator_composite_init_va(&composite, buffer, size, va); + va_end(va); - s_heap_size = size; - s_heap_start = buffer; + return_value_if_fail(s_allocator != NULL, RET_BAD_PARAMS); - s_allocator = mem_allocator_simple_init(&simple, buffer, size); if (size < 100 * 1024) { s_allocator = mem_allocator_pool_init(&pool, s_allocator, 100, 100, 80, 80, 32); } else if (size < 1000 * 1024) { @@ -105,6 +103,10 @@ ret_t tk_mem_init(void* buffer, uint32_t size) { return s_allocator != NULL ? RET_OK : RET_FAIL; } +ret_t tk_mem_init(void* buffer, uint32_t size) { + return tk_mem_init_ex(buffer, size, NULL, 0); +} + ret_t tk_mem_init_stage2(void) { return_value_if_fail(s_allocator != NULL, RET_FAIL); s_allocator = mem_allocator_lock_init(&s_lock, s_allocator); diff --git a/src/tkc/mem.h b/src/tkc/mem.h index 75432c836..0f4f0982b 100644 --- a/src/tkc/mem.h +++ b/src/tkc/mem.h @@ -140,6 +140,24 @@ void tk_mem_dump(void); */ ret_t tk_mem_init(void* buffer, uint32_t size); +/** + * @method tk_mem_init_ex + * @export none + * 初始化内存,支持多块不连续的内存。 + * >最后一个参数必须为NULL。 + * + * 示例: + * ```c + * tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL); + * ``` + * + * @param {void*} buffer 内存地址。 + * @param {uint32_t} size 内存长度。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...); + /** * @method tk_mem_init_stage2 * @export none diff --git a/src/tkc/mem_allocator_composite.h b/src/tkc/mem_allocator_composite.h new file mode 100644 index 000000000..f39500f06 --- /dev/null +++ b/src/tkc/mem_allocator_composite.h @@ -0,0 +1,226 @@ +/** + * File: mem_allocator_composite.h + * Author: AWTK Develop Team + * Brief: mem_allocator_composite + * + * Copyright (c) 2020 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-04-22 Li XianJing created + * + */ + +#ifndef TK_MEM_ALLOCATOR_COMPOSITE_H +#define TK_MEM_ALLOCATOR_COMPOSITE_H + +#include "tkc/mutex.h" +#include "tkc/mem_allocator_simple.h" + +BEGIN_C_DECLS + +/*最多支持的内存块数目*/ +#ifndef TK_MAX_MEM_BLOCK_NR +#define TK_MAX_MEM_BLOCK_NR 1 +#endif /*TK_MAX_MEM_BLOCK_NR*/ + +/** + * @class mem_allocator_composite_t + * @parent mem_allocator_t + * + * 支持多个不连续的内存块。 + * + */ +typedef struct _mem_allocator_composite_t { + mem_allocator_t allocator; + mem_allocator_simple_t allocators[TK_MAX_MEM_BLOCK_NR]; +} mem_allocator_composite_t; + +#define MEM_ALLOCATOR_COMPOSITE(allocator) ((mem_allocator_composite_t*)(allocator)) + +static inline void* mem_allocator_composite_alloc(mem_allocator_t* allocator, uint32_t size, + const char* func, uint32_t line) { + uint32_t i = 0; + void* addr = NULL; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_is_valid(iter)) { + addr = mem_allocator_alloc(iter, size, func, line); + if (addr != NULL) { + return addr; + } + } + } + + return NULL; +} + +static inline bool_t mem_allocator_composite_is_valid_addr(mem_allocator_t* allocator, void* ptr) { + uint32_t i = 0; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_contains(iter, ptr)) { + return TRUE; + } + } + + return FALSE; +} + +static inline void mem_allocator_composite_free(mem_allocator_t* allocator, void* ptr) { + uint32_t i = 0; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_contains(iter, ptr)) { + mem_allocator_free(iter, ptr); + break; + } + } + + return; +} + +static inline void* mem_allocator_composite_realloc(mem_allocator_t* allocator, void* ptr, + uint32_t size, const char* func, + uint32_t line) { + uint32_t i = 0; + void* addr = NULL; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + if (ptr == NULL) { + return mem_allocator_composite_alloc(allocator, size, func, line); + } + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_contains(iter, ptr)) { + addr = mem_allocator_realloc(iter, ptr, size, func, line); + if (addr == NULL) { + uint32_t old_size = mem_allocator_simple_get_mem_size(iter, ptr); + addr = mem_allocator_composite_alloc(allocator, size, func, line); + if (addr != NULL) { + uint32_t data_size = tk_min(old_size, size); + memcpy(addr, ptr, data_size); + mem_allocator_simple_free(iter, ptr); + } + } + break; + } + } + + return addr; +} + +static inline ret_t mem_allocator_composite_dump(mem_allocator_t* allocator) { + uint32_t i = 0; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_is_valid(iter)) { + mem_allocator_dump(iter); + } + } + + return RET_OK; +} + +static inline ret_t mem_allocator_composite_destroy(mem_allocator_t* allocator) { + uint32_t i = 0; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (mem_allocator_simple_is_valid(iter)) { + mem_allocator_destroy(iter); + } + } + allocator->vt = NULL; + + return RET_OK; +} + +static const mem_allocator_vtable_t s_mem_allocator_composite_vtable = { + .alloc = mem_allocator_composite_alloc, + .realloc = mem_allocator_composite_realloc, + .free = mem_allocator_composite_free, + .dump = mem_allocator_composite_dump, + .destroy = mem_allocator_composite_destroy}; + +static inline ret_t mem_allocator_composite_add_mem(mem_allocator_t* allocator, char* addr, + uint32_t size) { + uint32_t i = 0; + mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator); + + for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) { + mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i); + + if (!mem_allocator_simple_is_valid(iter)) { + mem_allocator_simple_init(MEM_ALLOCATOR_SIMPLE(iter), addr, size); + log_debug("add mem block %p %u\n", addr, size); + return RET_OK; + } + } + + log_warn("no space to add mem, please increase TK_MAX_MEM_BLOCK_NR\n"); + + return RET_BAD_PARAMS; +} + +static inline mem_allocator_t* mem_allocator_composite_init_va(mem_allocator_composite_t* composite, + void* buffer, uint32_t size, + va_list va) { + char* p = NULL; + mem_allocator_t* allocator = MEM_ALLOCATOR(composite); + return_value_if_fail(composite != NULL, NULL); + + memset(composite, 0x00, sizeof(*composite)); + allocator->vt = &s_mem_allocator_composite_vtable; + + ENSURE(mem_allocator_composite_add_mem(allocator, buffer, size) == RET_OK); + do { + p = va_arg(va, char*); + if (p != NULL) { + uint32_t s = va_arg(va, uint32_t); + ENSURE(mem_allocator_composite_add_mem(allocator, p, s) == RET_OK); + } + } while (p != NULL); + + return allocator; +} + +static inline mem_allocator_t* mem_allocator_composite_init(mem_allocator_composite_t* composite, + void* buffer, uint32_t size, ...) { + va_list va; + mem_allocator_t* ret = NULL; + + va_start(va, size); + ret = mem_allocator_composite_init_va(composite, buffer, size, va); + va_end(va); + + return ret; +} + +END_C_DECLS + +#endif /*TK_MEM_ALLOCATOR_COMPOSITE_H*/ diff --git a/src/tkc/mem_allocator_simple.h b/src/tkc/mem_allocator_simple.h index efa58d422..fea3a27b8 100644 --- a/src/tkc/mem_allocator_simple.h +++ b/src/tkc/mem_allocator_simple.h @@ -74,11 +74,9 @@ static void* tk_alloc_impl(mem_allocator_t* allocator, uint32_t s) { } if (iter == NULL) { - log_debug("%s: Out of memory(%d):\n", __FUNCTION__, (int)size); + return NULL; } - return_value_if_fail(iter != NULL, NULL); - /*如果找到的空闲块刚好满足需求,就从空闲块链表中移出它*/ if (iter->size < (size + MIN_SIZE)) { if (info->free_list == iter) { @@ -262,6 +260,19 @@ static inline void mem_allocator_simple_free(mem_allocator_t* allocator, void* p tk_free_impl(allocator, ptr); } +static inline bool_t mem_allocator_simple_is_valid(mem_allocator_t* allocator) { + mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info); + + return info->buffer != NULL && info->size > 0; +} + +static inline bool_t mem_allocator_simple_contains(mem_allocator_t* allocator, void* ptr) { + char* p = (char*)ptr; + mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info); + + return (p >= info->buffer && (p - info->buffer) < info->size); +} + static inline ret_t mem_allocator_simple_dump(mem_allocator_t* allocator) { mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info); log_debug("used: %u(max=%u) bytes %u(max=%u) blocks\n", info->used_bytes, info->used_max_bytes, @@ -271,6 +282,16 @@ static inline ret_t mem_allocator_simple_dump(mem_allocator_t* allocator) { return RET_OK; } +static uint32_t mem_allocator_simple_get_mem_size(mem_allocator_t* allocator, void* ptr) { + free_node_t* free_iter = NULL; + return_value_if_fail(ptr != NULL, 0); + + free_iter = (free_node_t*)((char*)ptr - sizeof(uint32_t)); + + return free_iter->size; +} + + static inline ret_t mem_allocator_simple_destroy(mem_allocator_t* allocator) { allocator->vt = NULL; return RET_OK; diff --git a/tests/SConscript b/tests/SConscript index 992d19f18..ebe873591 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -29,7 +29,6 @@ SOURCES = [ ] + Glob('*.cc') + Glob('*.c') env.Program(os.path.join(BIN_DIR, 'runTest'), SOURCES); -#env.Program(os.path.join(BIN_DIR, 'mem_test'), ["mem_test.cpp"]) env.Program(os.path.join(BIN_DIR, 'recycle_test'), ["recycle_test.cpp"]) env.Program(os.path.join(BIN_DIR, 'waitable_action_queue_test'), ["waitable_action_queue_test.cpp"]) env.Program(os.path.join(BIN_DIR, 'waitable_ring_buffer_test'), ["waitable_ring_buffer_test.cpp"]) diff --git a/tests/allocator_test.c b/tests/allocator_test.c index be948227d..0cb7466c6 100644 --- a/tests/allocator_test.c +++ b/tests/allocator_test.c @@ -1,15 +1,13 @@ -#include "tkc/mem_allocator_pool.h" +#include "tkc/mem.h" +#include "tkc/mem_allocator_pool.h" #include "tkc/mem_allocator_simple.h" -void allocator_test_basic() { +#include "tkc/mem_allocator_composite.h" + +void allocator_test_basic_ex(mem_allocator_t* allocator) { uint32_t i = 0; - char buff[102400]; void* addr = NULL; void* addrs[100]; - mem_allocator_simple_t simple; - mem_allocator_pool_t pool; - mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff)); - allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10); for (i = 0; i < ARRAY_SIZE(addrs); i++) { addr = mem_allocator_alloc(allocator, i + 1, __FUNCTION__, __LINE__); @@ -25,21 +23,31 @@ void allocator_test_basic() { mem_allocator_free(allocator, addrs[i]); } +} + +void allocator_test_basic() { + uint32_t i = 0; + char buff[102400]; + mem_allocator_simple_t simple; + mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff)); + mem_allocator_pool_t pool; + allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10); + + allocator_test_basic_ex(allocator); + for (i = 0; i < TK_MEM_POOLS_NR; i++) { assert(pool.pools[i]->used == 0); } + mem_allocator_destroy(allocator); + + return; } -void allocator_test_rand() { +void allocator_test_rand_ex(mem_allocator_t* allocator) { uint32_t k = 0; uint32_t i = 0; - char buff[1000 * 1000]; void* addr = NULL; void* addrs[1000]; - mem_allocator_simple_t simple; - mem_allocator_pool_t pool; - mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff)); - allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10); for (k = 0; k < 1000; k++) { for (i = 0; i < ARRAY_SIZE(addrs); i++) { @@ -57,12 +65,101 @@ void allocator_test_rand() { mem_allocator_free(allocator, addrs[i]); } } +} + +void allocator_test_rand() { + uint32_t i = 0; + char buff[1000 * 1000]; + mem_allocator_simple_t simple; + mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff)); + mem_allocator_pool_t pool; + + allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10); + + allocator_test_rand_ex(allocator); + for (i = 0; i < TK_MEM_POOLS_NR; i++) { assert(pool.pools[i]->used == 0); } + mem_allocator_destroy(allocator); +} + +void allocator_test_composite0() { + char mem1[100*1000]; + char mem2[1000*1000]; + char* addr = NULL; + mem_allocator_composite_t composite; + mem_allocator_t* allocator = mem_allocator_composite_init(&composite, mem1, sizeof(mem1), mem2, sizeof(mem2), NULL); + + allocator_test_basic_ex(allocator); + allocator_test_rand_ex(allocator); + mem_allocator_destroy(allocator); +} + +void allocator_test_composite1() { + char mem1[36]; + char mem2[64]; + char mem3[1280]; + char* addr = NULL; + mem_allocator_composite_t composite; + mem_allocator_t* allocator = mem_allocator_composite_init(&composite, mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL); + + /*mem1*/ + addr = mem_allocator_alloc(allocator, 16, __FUNCTION__, __LINE__); + assert(addr >= mem1); + assert(addr < (mem1 + sizeof(mem1))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + mem_allocator_free(allocator, addr); + addr = mem_allocator_alloc(allocator, 16, __FUNCTION__, __LINE__); + assert(addr >= mem1); + assert(addr < (mem1 + sizeof(mem1))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + addr = mem_allocator_realloc(allocator, addr, 16+2, __FUNCTION__, __LINE__); + assert(addr >= mem1); + assert(addr < (mem1 + sizeof(mem1))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + /*mem2*/ + addr = mem_allocator_alloc(allocator, 36, __FUNCTION__, __LINE__); + assert(addr >= mem2); + assert(addr < (mem2 + sizeof(mem2))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + mem_allocator_free(allocator, addr); + addr = mem_allocator_alloc(allocator, 36, __FUNCTION__, __LINE__); + assert(addr >= mem2); + assert(addr < (mem2 + sizeof(mem2))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + addr = mem_allocator_realloc(allocator, addr, 30, __FUNCTION__, __LINE__); + assert(addr >= mem2); + assert(addr < (mem2 + sizeof(mem2))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + /*mem3*/ + addr = mem_allocator_alloc(allocator, 66, __FUNCTION__, __LINE__); + assert(addr >= mem3); + assert(addr < (mem3 + sizeof(mem3))); + + mem_allocator_free(allocator, addr); + addr = mem_allocator_alloc(allocator, 66, __FUNCTION__, __LINE__); + assert(addr >= mem3); + assert(addr < (mem3 + sizeof(mem3))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + addr = mem_allocator_realloc(allocator, addr, 66+2, __FUNCTION__, __LINE__); + assert(addr >= mem3); + assert(addr < (mem3 + sizeof(mem3))); + assert(mem_allocator_composite_is_valid_addr(allocator, addr)); + + mem_allocator_destroy(allocator); + return; } void allocator_test() { + allocator_test_composite1(); allocator_test_basic(); allocator_test_rand(); }