Skip to content

Commit

Permalink
支持对齐内存的分配
Browse files Browse the repository at this point in the history
  • Loading branch information
copi143 committed Nov 9, 2024
1 parent 0e3fbbe commit bda8f77
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 59 deletions.
2 changes: 1 addition & 1 deletion include/define/config/alloc.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down
68 changes: 58 additions & 10 deletions include/libc-base/stdlib/alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 释放内存的回调函数
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 释放内存池中的内存
*
Expand All @@ -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);

//* ----------------------------------------------------------------------------------------------------
//& 内存管理器

Expand Down Expand Up @@ -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);
47 changes: 45 additions & 2 deletions src/kernel/mm/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
27 changes: 16 additions & 11 deletions src/libc-base/alloc/block.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
#pragma once
#include <libc-base.h>

#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)) // 是否有下一个块
Expand Down Expand Up @@ -101,7 +106,7 @@ finline void *blk_mergenext(void *ptr, blk_detach_t detach, void *data) {
return ptr;
}
/**
*\brief 尝试合并前后相邻块 (会清除块标记!)
*\brief 尝试合并前后相邻块 (会清除块释放标记!)
*
*\param ptr 块指针
*\param detach 用于(可合并时)将相邻块从空闲链表中移除的回调
Expand All @@ -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);
Expand Down
62 changes: 61 additions & 1 deletion src/libc-base/alloc/freelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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 中
*
Expand Down
Loading

0 comments on commit bda8f77

Please sign in to comment.