diff --git a/include/define/config/alloc.h b/include/define/config/alloc.h index 3fcc1d03..174c6448 100755 --- a/include/define/config/alloc.h +++ b/include/define/config/alloc.h @@ -1,7 +1,7 @@ #define ALLOC_FORCE_2M_PAGE 0 -#define ALLOC_LARGE_BLK_SIZE 16384 +#define ALLOC_LARGE_BLK_SIZE ((size_t)16384) // 默认认为分页大小是 4k // 如果是 2M 请调整为 2097152 diff --git a/include/libc-base/stdlib/alloc.h b/include/libc-base/stdlib/alloc.h index 53e4dc67..b1f0ab22 100755 --- a/include/libc-base/stdlib/alloc.h +++ b/include/libc-base/stdlib/alloc.h @@ -4,12 +4,25 @@ // 内存分配时大小和返回指针的对齐 (按照两倍字长) #define MALLOC_PADDING(size) (((size) + 2 * sizeof(size_t) - 1) & ~(2 * sizeof(size_t) - 1)) -#define SIZE_4k ((size_t)4096) -#define SIZE_2M ((size_t)(2 * 1024 * 1024)) +#define SIZE_4k ((size_t)4096) +#define SIZE_16k ((size_t)16384) +#define SIZE_2M ((size_t)(2 * 1024 * 1024)) +#define SIZE_1G ((size_t)(1024 * 1024 * 1024)) + +#ifndef ALLOC_LARGE_BLK_SIZE +# define ALLOC_LARGE_BLK_SIZE ((size_t)16384) +#endif + +#ifndef PAGE_SIZE +# define PAGE_SIZE ((size_t)4096) +#endif //* ---------------------------------------------------------------------------------------------------- //& 标准库内存分配函数 +// 这些函数应该由 libc 本体提供 +// 而在没有 libc 的情况下管理内存请使用下方的自定义内存分配函数 + dlimport void *malloc(size_t size) __THROW __attr_malloc __attr_allocsize(1); dlimport void *xmalloc(size_t size) __THROW __attr_malloc __attr_allocsize(1); dlimport void free(void *ptr) __THROW; @@ -40,6 +53,7 @@ dlimport void *valloc(size_t size) __THROW __attr_malloc __attr_allocsize(1); *\return 分配的内存地址 */ typedef void *(*cb_reqmem_t)(void *ptr, size_t size); + /** *\brief 释放内存的回调函数 * @@ -92,7 +106,7 @@ dlexport void sized_mpool_init(sized_mpool_t pool, void *ptr, size_t bsize, size dlexport void *sized_mpool_alloc(sized_mpool_t pool); /** - *\brief + *\brief 释放内存池中的内存 * *\param pool 内存池 *\param ptr param @@ -173,6 +187,16 @@ dlimport void mpool_setcb(mpool_t pool, cb_reqmem_t reqmem, cb_delmem_t delmem); */ dlimport void *mpool_alloc(mpool_t pool, size_t size); +/** + *\brief 从内存池中分配对齐的内存 + * + *\param pool 内存池 + *\param size 请求的内存大小 + *\param align 对齐大小 + *\return 分配的内存地址 + */ +dlexport void *mpool_aligned_alloc(mpool_t pool, size_t size, size_t align); + /** *\brief 释放内存池中的内存 * @@ -190,8 +214,28 @@ dlimport void mpool_free(mpool_t pool, void *ptr); */ dlimport size_t mpool_msize(mpool_t pool, void *ptr); +/** + *\brief 从内存池中重新分配内存 + * + *\param pool 内存池 + *\param ptr 要重新分配的内存地址 + *\param newsize 新的内存大小 + *\return 重新分配的内存地址 + */ dlimport void *mpool_realloc(mpool_t pool, void *ptr, size_t newsize); +/** + *\brief 从内存池中重新分配对齐的内存 + *! 注意 align 和第一次分配时的 align 必须相同 + * + *\param pool 内存池 + *\param ptr 要重新分配的内存地址 + *\param newsize 新的内存大小 + *\param align 对齐大小 + *\return 重新分配的内存地址 + */ +dlexport void *mpool_aligned_realloc(mpool_t pool, void *ptr, size_t newsize, size_t align); + //* ---------------------------------------------------------------------------------------------------- //& 内存管理器 @@ -221,18 +265,22 @@ typedef struct mman { large_blks_t large; // } *mman_t; -dlimport bool mman_init(mman_t pool, void *ptr, size_t size); +dlimport bool mman_init(mman_t man, void *ptr, size_t size); -dlimport size_t mman_total_size(mman_t pool); +dlimport size_t mman_total_size(mman_t man); -dlimport size_t mman_alloced_size(mman_t pool); +dlimport size_t mman_alloced_size(mman_t man); -dlimport void mman_setcb(mman_t pool, cb_reqmem_t reqmem, cb_delmem_t delmem); +dlimport void mman_setcb(mman_t man, cb_reqmem_t reqmem, cb_delmem_t delmem); -dlimport void *mman_alloc(mman_t pool, size_t size); +dlimport void *mman_alloc(mman_t man, size_t size); -dlimport void mman_free(mman_t pool, void *ptr); +dlexport void *mman_aligned_alloc(mman_t man, size_t size, size_t align); -dlimport size_t mman_msize(mman_t pool, void *ptr); +dlimport void mman_free(mman_t man, void *ptr); + +dlimport size_t mman_msize(mman_t man, void *ptr); dlimport void *mman_realloc(mman_t man, void *ptr, size_t newsize); + +dlexport void *mman_aligned_realloc(mman_t man, void *ptr, size_t newsize, size_t align); diff --git a/src/kernel/mm/mem.c b/src/kernel/mm/mem.c index 63b5f4fe..e3023142 100755 --- a/src/kernel/mm/mem.c +++ b/src/kernel/mm/mem.c @@ -36,15 +36,58 @@ void *malloc(size_t size) { return ptr; } +void *xmalloc(size_t size) { + void *ptr = malloc(size); + if (ptr == null) abort(); + return ptr; +} + void free(void *ptr) { // klogd("free %-10p %d", ptr, mpool_msize(&pool, ptr)); mpool_free(&pool, ptr); } +void *calloc(size_t n, size_t size) { + void *ptr = malloc(n * size); + if (ptr == null) return null; + memset(ptr, 0, n * size); + return ptr; +} + +void *realloc(void *ptr, size_t size) { + // void *old_ptr = ptr; + ptr = mpool_realloc(&pool, ptr, size); + // klogd("realloc %-10p %d -> %-10p %d", old_ptr, mpool_msize(&pool, ptr), ptr, size); + return ptr; +} + +void *reallocarray(void *ptr, size_t n, size_t size) { + return realloc(ptr, n * size); +} + +void *aligned_alloc(size_t align, size_t size) { + return mpool_aligned_alloc(&pool, size, align); +} + size_t malloc_usable_size(void *ptr) { return mpool_msize(&pool, ptr); } -void *realloc(void *ptr, size_t size) { - return mpool_realloc(&pool, ptr, size); +void *memalign(size_t align, size_t size) { + return mpool_aligned_alloc(&pool, size, align); +} + +int posix_memalign(void **memptr, size_t alignment, size_t size) { + void *ptr = mpool_aligned_alloc(&pool, size, alignment); + if (ptr == null) return 1; + *memptr = ptr; + return 0; +} + +void *pvalloc(size_t size) { + return aligned_alloc(4096, size); +} + +void *valloc(size_t size) { + return aligned_alloc(4096, size); } diff --git a/src/libc-base/alloc/block.h b/src/libc-base/alloc/block.h index c986a3d9..4f9cbf74 100755 --- a/src/libc-base/alloc/block.h +++ b/src/libc-base/alloc/block.h @@ -1,21 +1,26 @@ #pragma once #include +#if SIZE_MAX < UINT32_MAX +# error "The size of size_t is too small." +#endif + #define FREE_FLAG ((size_t)1) // 块释放标记 -#define AREA_FLAG ((size_t)2) // 分配区头尾标记 (防止块查找越界) -#define SIZE_FLAG ((size_t)4) // 2M 分配区标记 +#define AREA_FLAG ((size_t)2) // 分配区头尾标记 (防止块查找越界) (禁止为块设置该标记) +#define SIZE_FLAG ((size_t)4) // 2M 分配区标记 (仅对多分配区有效) (为 2M 分配区内所有块设置该标记) #define FLAG_BITS ((size_t)7) // 所有标志位 // 两倍字长对齐和 16k 对齐 #define PADDING(size) (((size) + 2 * sizeof(size_t) - 1) & ~(2 * sizeof(size_t) - 1)) #define PADDING_4k(size) (((size) + SIZE_4k - 1) & ~(size_t)(SIZE_4k - 1)) -#define PADDING_16k(size) (((size) + 16384 - 1) & ~(size_t)(16384 - 1)) +#define PADDING_16k(size) (((size) + SIZE_16k - 1) & ~(size_t)(SIZE_16k - 1)) #define PADDING_2M(size) (((size) + SIZE_2M - 1) & ~(size_t)(SIZE_2M - 1)) +#define PADDING_1G(size) (((size) + SIZE_1G - 1) & ~(size_t)(SIZE_1G - 1)) -#define blk_prevtail(ptr) (((size_t *)ptr)[-2]) -#define blk_head(ptr) (((size_t *)ptr)[-1]) -#define blk_tail(ptr, size) (((size_t *)(ptr + size))[0]) -#define blk_nexthead(ptr, size) (((size_t *)(ptr + size))[1]) +#define blk_prevtail(ptr) (((size_t *)ptr)[-2]) // 上一个块的尾部标记 +#define blk_head(ptr) (((size_t *)ptr)[-1]) // 块头部标记 +#define blk_tail(ptr, size) (((size_t *)(ptr + size))[0]) // 块尾部标记 +#define blk_nexthead(ptr, size) (((size_t *)(ptr + size))[1]) // 下一个块的头部标记 #define blk_noprev(ptr) ((bool)(blk_prevtail(ptr) & AREA_FLAG)) // 是否有上一个块 #define blk_nonext(ptr, size) ((bool)(blk_nexthead(ptr, size) & AREA_FLAG)) // 是否有下一个块 @@ -101,7 +106,7 @@ finline void *blk_mergenext(void *ptr, blk_detach_t detach, void *data) { return ptr; } /** - *\brief 尝试合并前后相邻块 (会清除块标记!) + *\brief 尝试合并前后相邻块 (会清除块释放标记!) * *\param ptr 块指针 *\param detach 用于(可合并时)将相邻块从空闲链表中移除的回调 @@ -122,11 +127,11 @@ finline void *blk_trymerge(void *ptr, blk_detach_t detach, void *data) { } /** - *\brief 将一个块分割成两个 (会清除块标记!) + *\brief 将一个块分割成两个 (会清除块释放标记!) * *\param ptr 块指针 - *\param size 分割出第一个块的大小 - *\return value + *\param size 分割出第一个块的大小 (必须对齐到 2 倍字长!) + *\return 第二个块的指针 */ finline void *blk_split(void *ptr, size_t size) { bool is_2M = blk_area_is_2M(ptr); diff --git a/src/libc-base/alloc/freelist.h b/src/libc-base/alloc/freelist.h index 5de461d5..3d90d818 100755 --- a/src/libc-base/alloc/freelist.h +++ b/src/libc-base/alloc/freelist.h @@ -22,6 +22,13 @@ finline int freelists_size2id(size_t size) { return (32 - 9) - __builtin_clz(size) + 2; } +/** + *\brief 将 freelist 中的内存块分离 + * + *\param list 空闲链表 + *\param ptr 要分离的内存块指针 + *\return 分离后的空闲链表 + */ finline freelist_t freelist_detach(freelist_t list, freelist_t ptr) { if (list == ptr) return ptr->next; if (ptr->next) ptr->next->prev = ptr->prev; @@ -35,7 +42,7 @@ finline freelist_t freelist_detach(freelist_t list, freelist_t ptr) { *\param lists 空闲链表组 *\param id 空闲链表的 id *\param ptr 要分离的内存块指针 - *\return value + *\return 分离的内存块指针 (即传入的 ptr) */ finline void *freelists_detach(freelists_t lists, int id, freelist_t ptr) { if (lists[id] == ptr) { @@ -48,6 +55,13 @@ finline void *freelists_detach(freelists_t lists, int id, freelist_t ptr) { return ptr; } +/** + *\brief 匹配并将内存从 freelist 中分离 + * + *\param list_p 空闲链表指针 + *\param size 要寻找内存的最小大小 + *\return 找到的内存块指针,未找到为 null + */ finline void *freelist_match(freelist_t *list_p, size_t size) { for (freelist_t list = *list_p; list != null; list = list->next) { size_t tgt_size = blk_size(list); @@ -78,6 +92,52 @@ finline void *freelists_match(freelists_t lists, size_t size) { return null; } +#define aligned_size_of(ptr, align) \ + ((ssize_t)blk_size(ptr) - (ssize_t)(PADDING_UP(ptr, align) - (size_t)(ptr))) + +/** + *\brief 匹配并将内存从 freelist 中分离 + * 要求内存能对齐到 align 指定的大小且对齐后至少有 size 的大小 + * + *\param list_p 空闲链表指针 + *\param size 要寻找内存的最小大小 + *\param align 对齐大小 (必须为 2 的幂) (必须大于等于 2 倍字长) + *\return 找到的内存块指针,未找到为 null + */ +finline void *freelist_aligned_match(freelist_t *list_p, size_t size, size_t align) { + for (freelist_t list = *list_p; list != null; list = list->next) { + ssize_t tgt_size = aligned_size_of(list, align); + if (tgt_size >= size) { + *list_p = freelist_detach(*list_p, list); + return list; + } + } + return null; +} + +/** + *\brief 匹配并将内存从 freelist 中分离 + * 要求内存能对齐到 align 指定的大小且对齐后至少有 size 的大小 + * + *\param lists 空闲链表 (组) + *\param size 要寻找内存的最小大小 + *\param align 对齐大小 (必须为 2 的幂) (必须大于等于 2 倍字长) + *\return 找到的内存块指针,未找到为 null + */ +finline void *freelists_aligned_match(freelists_t lists, size_t size, size_t align) { + int id = freelists_size2id(size); + if (id < 0) return null; + for (; id < FREELIST_NUM; id++) { + for (freelist_t list = lists[id]; list != null; list = list->next) { + ssize_t tgt_size = aligned_size_of(list, align); + if (tgt_size >= size) return freelists_detach(lists, id, list); + } + } + return null; +} + +#undef aligned_size_of + /** *\brief 将元素放到 freelist 中 * diff --git a/src/libc-base/alloc/large-blk.h b/src/libc-base/alloc/large-blk.h index 75dadd15..40e47599 100755 --- a/src/libc-base/alloc/large-blk.h +++ b/src/libc-base/alloc/large-blk.h @@ -1,8 +1,6 @@ #pragma once #include -// ALLOC_LARGE_BLK_SIZE - #include "freelist.h" struct large_blk { @@ -12,10 +10,18 @@ struct large_blk { size_t size; }; -finline large_blk_t *large_blk_blokp(large_blks_t blks, void *ptr) __attr(pure); +finline large_blk_t *large_blk_blokp(large_blks_t blks, void *ptr) __attr(const); +/** + *\brief 获取大内存块应该放入的空闲链表 + * + *\param blks 大内存块空闲链表 (组) + *\param ptr 大内存块指针 + *\return 大块内存空闲链表指针 + */ finline large_blk_t *large_blk_blokp(large_blks_t blks, void *ptr) { - return blks + ((size_t)ptr / SIZE_4k) % LARGEBLKLIST_NUM; + size_t hash = ((size_t)ptr / SIZE_4k | (size_t)ptr / SIZE_4k / LARGEBLKLIST_NUM / 2); + return blks + hash % LARGEBLKLIST_NUM; } finline large_blk_t large_blk_put(large_blks_t blks, void *ptr, size_t size) { @@ -36,7 +42,15 @@ finline large_blk_t large_blk_find(large_blks_t blks, void *ptr) { return null; } -// 保证 size 大于 ALLOC_LARGE_BLK_SIZE +/** + *\brief 分配大块内存 + * + *\param size 请求的内存大小 (保证其大于 ALLOC_LARGE_BLK_SIZE) + *\param blks 大内存块空闲链表 (组) + *\param reqmem 请求内存的回调函数 + *\param delmem 释放内存的回调函数 + *\return 分配的内存地址 + */ finline void *large_blk_alloc(size_t size, large_blks_t blks, cb_reqmem_t reqmem, cb_delmem_t delmem) { size = PADDING_4k(size); @@ -54,6 +68,15 @@ finline void *large_blk_alloc(size_t size, large_blks_t blks, cb_reqmem_t reqmem return ptr; } +/** + *\brief 释放大块内存 + * 可以传入任何指针,非大内存块会返回 false + * + *\param blks 大内存块空闲链表 (组) + *\param ptr 大内存块指针 + *\param delmem 释放内存的回调函数 + *\return 是否释放成功 + */ finline bool large_blk_free(large_blks_t blks, void *ptr, cb_delmem_t delmem) { large_blk_t *blk_p = large_blk_blokp(blks, ptr); auto blk = large_blk_find(blks, ptr); diff --git a/src/libc-base/alloc/mman.c b/src/libc-base/alloc/mman.c index e3b3c8ed..1de89452 100755 --- a/src/libc-base/alloc/mman.c +++ b/src/libc-base/alloc/mman.c @@ -132,16 +132,14 @@ finline bool try_split_and_free(mman_t man, void *ptr, size_t size) { } dlexport void *mman_alloc(mman_t man, size_t size) { - if (size == 0) size = 2 * sizeof(size_t); - size = PADDING(size); + size = size == 0 ? 2 * sizeof(size_t) : PADDING(size); // 保证最小分配 2 个字长且对齐到 2 倍字长 if (size >= ALLOC_LARGE_BLK_SIZE) { return large_blk_alloc(size, man->large, man->cb_reqmem, man->cb_delmem); } - void *ptr = freelists_match(man->freed, size); - - if (ptr == null) ptr = freelist_match(&man->large_blk, size); + // 优先从空闲链表中分配 + void *ptr = freelists_match(man->freed, size) ?: freelist_match(&man->large_blk, size); if (ptr == null) { // 不足就分配 if (!mman_reqmem(man, size)) return null; @@ -158,6 +156,46 @@ dlexport void *mman_alloc(mman_t man, size_t size) { return ptr; } +dlexport void *mman_aligned_alloc(mman_t man, size_t size, size_t align) { + if (align & (align - 1)) return null; // 不是 2 的幂次方 + if (align < 2 * sizeof(size_t)) return mman_alloc(man, size); // 对齐小于 2 倍指针大小 + size = size == 0 ? 2 * sizeof(size_t) : PADDING(size); // 保证最小分配 2 个字长且对齐到 2 倍字长 + + if (size >= ALLOC_LARGE_BLK_SIZE) { + void *ptr = large_blk_alloc(size, man->large, man->cb_reqmem, man->cb_delmem); + if ((size_t)ptr % align != 0) { // TODO 让这种情况永远不会出现 + large_blk_free(man->large, ptr, man->cb_delmem); + ptr = null; + } + return ptr; + } + + // 优先从空闲链表中分配 + void *ptr = freelists_aligned_match(man->freed, size, align) + ?: freelist_aligned_match(&man->large_blk, size, align); + + if (ptr == null) { // 不足就分配 + if (!mman_reqmem(man, size)) return null; + ptr = freelist_aligned_match(&man->large_blk, size, align); + if (ptr == null) return null; // TODO 让这种情况永远不会出现 + } + + size_t offset = (size_t)ptr % align; + if (offset > 0) { + void *new_ptr = blk_split(ptr, offset - 2 * sizeof(size_t)); + do_free(man, new_ptr); + } + + try_split_and_free(man, ptr, size); + + size = blk_size(ptr); + blk_setalloced(ptr, size); + mman_pool_t pool = blk_poolptr(ptr); + pool->alloced_size += size; + man->alloced_size += size; + return ptr; +} + dlexport void mman_free(mman_t man, void *ptr) { if (ptr == null) return; @@ -170,8 +208,6 @@ dlexport void mman_free(mman_t man, void *ptr) { pool->alloced_size -= size; man->alloced_size -= size; - size_t areasize = blk_area_is_2M(ptr) ? SIZE_2M : SIZE_4k; - ptr = blk_trymerge(ptr, (blk_detach_t)_detach, man); if (pool != &man->main && pool->alloced_size == 0) { if (mman_delmem(man, pool)) return; @@ -191,21 +227,64 @@ dlexport void *mman_realloc(mman_t man, void *ptr, size_t newsize) { size_t size = blk_size(ptr); if (size >= newsize) { - try_split_and_free(man, ptr, newsize); + if ((size_t)ptr % SIZE_4k == 0) { + if (size - newsize >= 2 * SIZE_4k) goto L1; + } else { + try_split_and_free(man, ptr, newsize); + } return ptr; } +L1: + + if ((size_t)ptr % SIZE_4k != 0) { + void *next = blk_next(ptr); + if (next != null && blk_freed(next)) { + size_t total_size = size + 2 * sizeof(size_t) + blk_size(next); + if (total_size >= newsize) { + ptr = blk_mergenext(ptr, (blk_detach_t)_detach, man); + try_split_and_free(man, ptr, newsize); + return ptr; + } + } + } - void *next = blk_next(ptr); - if (next != null && blk_freed(next)) { - size_t total_size = size + 2 * sizeof(size_t) + blk_size(next); - if (total_size >= newsize) { - ptr = blk_mergenext(ptr, (blk_detach_t)_detach, man); + void *new_ptr = mman_alloc(man, newsize); + memcpy(new_ptr, ptr, size); + mman_free(man, ptr); + return new_ptr; +} + +//! 注意 align 和第一次分配时的 align 必须相同 +dlexport void *mman_aligned_realloc(mman_t man, void *ptr, size_t newsize, size_t align) { + if (ptr == null) return mman_aligned_alloc(man, newsize, align); + if (align & (align - 1)) return null; // 不是 2 的幂次方 + if (align < 2 * sizeof(size_t)) return mman_realloc(man, ptr, newsize); // 对齐小于 2 倍指针大小 + newsize = newsize == 0 ? 2 * sizeof(size_t) : PADDING(newsize); + + size_t size = blk_size(ptr); + if (size >= newsize) { + if ((size_t)ptr % SIZE_4k == 0) { + if (size - newsize >= 2 * SIZE_4k) goto L1; + } else { try_split_and_free(man, ptr, newsize); - return ptr; + } + return ptr; + } +L1: + + if ((size_t)ptr % SIZE_4k != 0) { + void *next = blk_next(ptr); + if (next != null && blk_freed(next)) { + size_t total_size = size + 2 * sizeof(size_t) + blk_size(next); + if (total_size >= newsize) { + ptr = blk_mergenext(ptr, (blk_detach_t)_detach, man); + try_split_and_free(man, ptr, newsize); + return ptr; + } } } - void *new_ptr = mman_alloc(man, newsize); + void *new_ptr = mman_aligned_alloc(man, newsize, align); memcpy(new_ptr, ptr, size); mman_free(man, ptr); return new_ptr; diff --git a/src/libc-base/alloc/pool.c b/src/libc-base/alloc/pool.c index 35f03ae6..17494ff0 100755 --- a/src/libc-base/alloc/pool.c +++ b/src/libc-base/alloc/pool.c @@ -92,12 +92,10 @@ finline bool try_split_and_free(mpool_t pool, void *ptr, size_t size) { } dlexport void *mpool_alloc(mpool_t pool, size_t size) { - if (size == 0) size = 2 * sizeof(size_t); - size = PADDING(size); + size = size == 0 ? 2 * sizeof(size_t) : PADDING(size); // 保证最小分配 2 个字长且对齐到 2 倍字长 - void *ptr = freelists_match(pool->freed, size); - - if (ptr == null) ptr = freelist_match(&pool->large_blk, size); + // 优先从空闲链表中分配 + void *ptr = freelists_match(pool->freed, size) ?: freelist_match(&pool->large_blk, size); if (ptr == null) { // 不足就分配 if (!mpool_reqmem(pool, size)) return null; @@ -112,6 +110,35 @@ dlexport void *mpool_alloc(mpool_t pool, size_t size) { return ptr; } +dlexport void *mpool_aligned_alloc(mpool_t pool, size_t size, size_t align) { + if (align & (align - 1)) return null; // 不是 2 的幂次方 + if (align < 2 * sizeof(size_t)) return mpool_alloc(pool, size); // 对齐小于 2 倍指针大小 + size = size == 0 ? 2 * sizeof(size_t) : PADDING(size); // 保证最小分配 2 个字长且对齐到 2 倍字长 + + // 优先从空闲链表中分配 + void *ptr = freelists_aligned_match(pool->freed, size, align) + ?: freelist_aligned_match(&pool->large_blk, size, align); + + if (ptr == null) { // 不足就分配 + if (!mpool_reqmem(pool, size)) return null; + ptr = freelist_aligned_match(&pool->large_blk, size, align); + if (ptr == null) return null; // TODO 让这种情况永远不会出现 + } + + size_t offset = (size_t)ptr % align; + if (offset > 0) { + void *new_ptr = blk_split(ptr, offset - 2 * sizeof(size_t)); + do_free(pool, new_ptr); + } + + try_split_and_free(pool, ptr, size); + + size = blk_size(ptr); + blk_setalloced(ptr, size); + pool->alloced_size += size; + return ptr; +} + dlexport void mpool_free(mpool_t pool, void *ptr) { if (ptr == null) return; @@ -128,8 +155,7 @@ dlexport size_t mpool_msize(mpool_t pool, void *ptr) { dlexport void *mpool_realloc(mpool_t pool, void *ptr, size_t newsize) { if (ptr == null) return mpool_alloc(pool, newsize); - if (newsize == 0) newsize = 2 * sizeof(size_t); - newsize = PADDING(newsize); + newsize = newsize == 0 ? 2 * sizeof(size_t) : PADDING(newsize); size_t size = blk_size(ptr); if (size >= newsize) { @@ -152,3 +178,32 @@ dlexport void *mpool_realloc(mpool_t pool, void *ptr, size_t newsize) { mpool_free(pool, ptr); return new_ptr; } + +//! 注意 align 和第一次分配时的 align 必须相同 +dlexport void *mpool_aligned_realloc(mpool_t pool, void *ptr, size_t newsize, size_t align) { + if (ptr == null) return mpool_aligned_alloc(pool, newsize, align); + if (align & (align - 1)) return null; // 不是 2 的幂次方 + if (align < 2 * sizeof(size_t)) return mpool_realloc(pool, ptr, newsize); // 对齐小于 2 倍指针大小 + newsize = newsize == 0 ? 2 * sizeof(size_t) : PADDING(newsize); + + size_t size = blk_size(ptr); + if (size >= newsize) { + try_split_and_free(pool, ptr, newsize); + return ptr; + } + + void *next = blk_next(ptr); + if (next != null && blk_freed(next)) { + size_t total_size = size + 2 * sizeof(size_t) + blk_size(next); + if (total_size >= newsize) { + ptr = blk_mergenext(ptr, (blk_detach_t)_detach, pool); + try_split_and_free(pool, ptr, newsize); + return ptr; + } + } + + void *new_ptr = mpool_aligned_alloc(pool, newsize, align); + memcpy(new_ptr, ptr, size); + mpool_free(pool, ptr); + return new_ptr; +} diff --git a/src/libc/alloc.c b/src/libc/alloc.c index 9eedb348..f20b3361 100755 --- a/src/libc/alloc.c +++ b/src/libc/alloc.c @@ -34,11 +34,7 @@ void *reallocarray(void *ptr, size_t n, size_t size) { } void *aligned_alloc(size_t align, size_t size) { - if (!(align & (align - 1)) && align <= 2 * sizeof(size_t)) return mman_alloc(&mman, size); - void *ptr = malloc(size + align - 1); - if (ptr == null) return null; - ptr = (ptr + align - 1) - (size_t)(ptr + align - 1) % align; - return ptr; + return mman_aligned_alloc(&mman, size, align); } size_t malloc_usable_size(void *ptr) { @@ -46,11 +42,11 @@ size_t malloc_usable_size(void *ptr) { } void *memalign(size_t align, size_t size) { - return aligned_alloc(align, size); + return mman_aligned_alloc(&mman, size, align); } int posix_memalign(void **memptr, size_t alignment, size_t size) { - void *ptr = aligned_alloc(alignment, size); + void *ptr = mman_aligned_alloc(&mman, size, alignment); if (ptr == null) return 1; *memptr = ptr; return 0;