From 9df92922ab384295380d4414493e69983671dbf5 Mon Sep 17 00:00:00 2001 From: Water-Melon Date: Sat, 18 Jan 2025 14:55:19 +0000 Subject: [PATCH] feat(alloc): support capacity limit 1. Add capacity limit. 2. Add an API to retrieve the current available memory size. https://github.com/Water-Melon/Melon/issues/32 --- docs/Melon Developer Guide.txt | 19 +- docs/book/cn/mpool.md | 25 +- docs/book/en/mpool.md | 25 +- include/mln_alloc.h | 673 +----------------------------- include/mln_parser_generator.h | 2 +- src/mln_alloc.c | 718 +++++++++++++++++++++++++++++++++ src/mln_conf.c | 2 +- src/mln_connection.c | 2 +- src/mln_expr.c | 4 +- src/mln_file.c | 2 +- src/mln_lang.c | 4 +- src/mln_lang_array.c | 7 - src/mln_lang_ast.c | 2 +- src/mln_lang_bool.c | 7 - src/mln_lang_func.c | 7 - src/mln_lang_int.c | 7 - src/mln_lang_nil.c | 7 - src/mln_lang_obj.c | 7 - src/mln_lang_real.c | 7 - src/mln_lang_str.c | 7 - t/alloc.c | 2 +- t/chain.c | 2 +- t/lex.c | 2 +- t/parser_generator.c | 2 +- 24 files changed, 801 insertions(+), 741 deletions(-) diff --git a/docs/Melon Developer Guide.txt b/docs/Melon Developer Guide.txt index c4244b96..14c46bce 100644 --- a/docs/Melon Developer Guide.txt +++ b/docs/Melon Developer Guide.txt @@ -1299,10 +1299,11 @@ Their definitions can be found in melon/include/mln_types.h. 16) Memory Pool The memory pool can help developer use memory more easily. - a) mln_alloc_t *mln_alloc_init(mln_alloc_t *parent); + a) mln_alloc_t *mln_alloc_init(mln_alloc_t *parent, mln_size_t capacity); Initialize a memory pool object. 'parent' is another memory pool, which means a memory pool can be created by another pool. If 'parent' is NULL, memory pool will be created from heap. + `capacity` is the capacity limit of the pool. If it is set to `0`, the capacity would be unlimited. b) void mln_alloc_destroy(mln_alloc_t *pool); Destroy a memory pool object and free all memory blocks that it allocated. @@ -1321,9 +1322,9 @@ Their definitions can be found in melon/include/mln_types.h. f) void mln_alloc_free(void *ptr); Free a memory block to a memory pool. - g) mln_alloc_t *mln_alloc_shm_init(mln_size_t size, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); + g) mln_alloc_t *mln_alloc_shm_init(mln_size_t capacity, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); Initialize a shared memory pool. - `size` - shared memory size + `capacity` - shared memory capacity `locker` - lock `lock` - lock handler `unlock` - unlock handler @@ -1333,6 +1334,18 @@ Their definitions can be found in melon/include/mln_types.h. 'lock' and 'unlock' will be called only in sub-pool functions. So user should lock or unlock by yourself when operate shared memory pool directly. + h) mln_size_t mln_alloc_available_capacity(mln_alloc_t *pool); + Retrieve the current available capacity of the memory pool (if a capacity limit is set for the memory pool). + For heap memory pools, when calling `mln_alloc_m`, several memory blocks similar in size to the requested allocation may be + pre-allocated. In such cases, the value returned by this function does not include the memory size of these pre-allocated + but unused blocks. + + Heap Memory: If the second parameter (`capacity`) in `mln_alloc_init` is not `0`, the function returns the current + available memory size of the memory pool (refer to the note above for details). If it is `0`, the function returns + `MLN_ALLOC_INFINITE_SIZE`. + + Shared Memory: Returns the total size of all available memory regions in bytes. + 17) Chain & Buf These two structures do not have interfaces to operate. We should set them manually. Just like buf and chain in Nginx. diff --git a/docs/book/cn/mpool.md b/docs/book/cn/mpool.md index 5e2a805c..eda8d4c2 100644 --- a/docs/book/cn/mpool.md +++ b/docs/book/cn/mpool.md @@ -30,10 +30,10 @@ Melon中,内存池分为两类: #### mln_alloc_init ```c -mln_alloc_t *mln_alloc_init(mln_alloc_t *parent); +mln_alloc_t *mln_alloc_init(mln_alloc_t *parent, mln_size_t capacity); ``` -描述:创建堆内存内存池。参数`parent`是一个内存池实例,该参数为`NULL`时,本函数创建的内存池将从堆中分配内存,若不为`NULL`时,则从`parent`所在池中分配内存。即池结构可级联。 +描述:创建堆内存内存池。参数`parent`是一个内存池实例,该参数为`NULL`时,本函数创建的内存池将从堆中分配内存,若不为`NULL`时,则从`parent`所在池中分配内存。即池结构可级联。`capacity`是用于限制内存池容量的,当它的值为`0`时,表示内存池容量不受限,也就是跟随系统内存容量。 返回值:成功则返回内存池结构指针,否则返回`NULL` @@ -42,14 +42,14 @@ mln_alloc_t *mln_alloc_init(mln_alloc_t *parent); #### mln_alloc_shm_init ```c -mln_alloc_t *mln_alloc_shm_init(mln_size_t size, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); +mln_alloc_t *mln_alloc_shm_init(mln_size_t capacity, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); ``` 描述:创建共享内存内存池。 参数: -- `size` 本池建立时需要给出池大小`size`(单位字节),一旦创建完毕后则后续无法再扩大。 +- `capacity` 本池建立时需要给出池大小(单位字节),一旦创建完毕后则后续无法再扩大。 - `locker` 是锁资源结构指针。 - `lock` 是用于对锁资源加锁的回调函数,该函数参数为锁资源指针。若加锁失败则返回`非0`值。 - `unlock` 是用于对锁资源解锁的回调函数,该函数参数为锁资源指针。若解锁失败则返回`非0`值。 @@ -126,6 +126,23 @@ void mln_alloc_free(void *ptr); +#### mln_alloc_available_capacity + +```c +mln_size_t mln_alloc_available_capacity(mln_alloc_t *pool); +``` + +描述:获取当前内存池剩余可用容量(如果内存池设置了容量限制)。 + +注意:对于堆内存池,当调用`mln_alloc_m`时会欲分配若干与申请大小相似的内存块。在这种情况下,本函数返回的数值并不包含这些被预分配且未被使用的块的内存大小。 + +返回值: + +- 堆内存:若在`mln_alloc_init`时第二个参数(`capacity`)不为`0`,则返回当前内存池剩余可用内存大小(详情参考上面注意事项),若为`0`,则返回`M_ALLOC_INFINITE_SIZE`。 +- 共享内存:返回全部可用内存区的字节大小。 + + + ### 示例 ```c diff --git a/docs/book/en/mpool.md b/docs/book/en/mpool.md index 4e6f8c34..4d2d7107 100644 --- a/docs/book/en/mpool.md +++ b/docs/book/en/mpool.md @@ -32,10 +32,10 @@ Among them, the shared memory memory pool only allows data to be shared between #### mln_alloc_init ```c -mln_alloc_t *mln_alloc_init(mln_alloc_t *parent); +mln_alloc_t *mln_alloc_init(mln_alloc_t *parent, mln_size_t capacity); ``` -Description: Create a heap memory memory pool. The parameter `parent` is a memory pool instance. When the parameter is `NULL`, the memory pool created by this function will allocate memory from the heap. If it is not `NULL`, it will allocate memory from the pool where `parent` is located. That is, the pool structure can be cascaded. +Description: Create a heap memory memory pool. The parameter `parent` is a memory pool instance. When the parameter is `NULL`, the memory pool created by this function will allocate memory from the heap. If it is not `NULL`, it will allocate memory from the pool where `parent` is located. That is, the pool structure can be cascaded. `capacity` is used to limit the memory pool's capacity. When its value is `0`, it indicates that the memory pool capacity is unlimited, meaning it follows the system's available memory capacity. Return value: If successful, return the memory pool structure pointer, otherwise return `NULL` @@ -44,14 +44,14 @@ Return value: If successful, return the memory pool structure pointer, otherwise #### mln_alloc_shm_init ```c -mln_alloc_t *mln_alloc_shm_init(mln_size_t size, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); +mln_alloc_t *mln_alloc_shm_init(mln_size_t capacity, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); ``` Description: Create a shared memory memory pool. Parameters: -- `size` The pool size `size` (in bytes) needs to be given when creating this pool. Once created, it cannot be expanded later. +- `capacity` The pool size (in bytes) needs to be given when creating this pool. Once created, it cannot be expanded later. - `locker` is the lock resource pointer. - `lock` is a callback function used to lock the lock resource. The function parameter is the lock resource pointer. If the lock fails, a `non-0` value is returned. - `unlock` is a callback function used to unlock the lock resource. The function parameter is the lock resource pointer. If unlocking fails, a `non-0` value is returned. @@ -128,6 +128,23 @@ Return value: none +#### mln_alloc_available_capacity + +```c +mln_size_t mln_alloc_available_capacity(mln_alloc_t *pool); +``` + +Description: Retrieve the current available capacity of the memory pool (if a capacity limit is set for the memory pool). + +Note: For heap memory pools, when calling `mln_alloc_m`, several memory blocks similar in size to the requested allocation may be pre-allocated. In such cases, the value returned by this function does not include the memory size of these pre-allocated but unused blocks. + +Return Values: + +Heap Memory: If the second parameter (`capacity`) in `mln_alloc_init` is not `0`, the function returns the current available memory size of the memory pool (refer to the note above for details). If it is `0`, the function returns `M_ALLOC_INFINITE_SIZE`. +Shared Memory: Returns the total size of all available memory regions in bytes. + + + ### Example ```c diff --git a/include/mln_alloc.h b/include/mln_alloc.h index 732b35a0..e0b0d94e 100644 --- a/include/mln_alloc.h +++ b/include/mln_alloc.h @@ -33,6 +33,7 @@ typedef int (*mln_alloc_shm_lock_cb_t)(void *); #define M_ALLOC_SHM_BIT_SIZE 64 #define M_ALLOC_SHM_LARGE_SIZE (1*1024+512)*1024 #define M_ALLOC_SHM_DEFAULT_SIZE 2*1024*1024 +#define M_ALLOC_INFINITE_SIZE (~((mln_size_t)0)) typedef struct mln_alloc_s mln_alloc_t; typedef struct mln_alloc_mgr_s mln_alloc_mgr_t; @@ -65,6 +66,7 @@ struct mln_alloc_chunk_s { mln_size_t count; mln_alloc_mgr_t *mgr; mln_alloc_blk_t *blks[M_ALLOC_BLK_NUM+1]; + mln_size_t size; }; struct mln_alloc_mgr_s { @@ -99,7 +101,8 @@ struct mln_alloc_s { #else void *mem; #endif - mln_size_t shm_size; + mln_size_t capacity; + mln_size_t in_used; void *locker; mln_alloc_shm_lock_cb_t lock; mln_alloc_shm_lock_cb_t unlock; @@ -118,666 +121,14 @@ struct mln_alloc_s { #define mln_alloc_is_shm(pool) (pool->mem != NULL) -static inline mln_alloc_t *mln_alloc_shm_init(mln_size_t size, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); -static inline mln_alloc_t *mln_alloc_init(mln_alloc_t *parent); -static inline void mln_alloc_destroy(mln_alloc_t *pool); -static inline void *mln_alloc_m(mln_alloc_t *pool, mln_size_t size); -static inline void *mln_alloc_c(mln_alloc_t *pool, mln_size_t size); -static inline void *mln_alloc_re(mln_alloc_t *pool, void *ptr, mln_size_t size); -static inline void mln_alloc_free(void *ptr); - -MLN_CHAIN_FUNC_DECLARE(static inline, \ - mln_blk, \ - mln_alloc_blk_t, ); -MLN_CHAIN_FUNC_DECLARE(static inline, \ - mln_chunk, \ - mln_alloc_chunk_t, ); -MLN_CHAIN_FUNC_DECLARE(static inline, \ - mln_alloc_shm, \ - mln_alloc_shm_t, ); -static inline void -mln_alloc_mgr_table_init(mln_alloc_mgr_t *tbl); -static inline mln_alloc_mgr_t * -mln_alloc_get_mgr_by_size(mln_alloc_mgr_t *tbl, mln_size_t size); -static inline void *mln_alloc_shm_m(mln_alloc_t *pool, mln_size_t size); -static inline void *mln_alloc_shm_large_m(mln_alloc_t *pool, mln_size_t size); -static inline int mln_alloc_shm_allowed(mln_alloc_shm_t *as, mln_off_t *Boff, mln_off_t *boff, mln_size_t size); -static inline void *mln_alloc_shm_set_bitmap(mln_alloc_shm_t *as, mln_off_t Boff, mln_off_t boff, mln_size_t size); -static inline mln_alloc_shm_t *mln_alloc_shm_new_block(mln_alloc_t *pool, mln_off_t *Boff, mln_off_t *boff, mln_size_t size); -static inline void mln_alloc_free_shm(void *ptr); - -static inline mln_alloc_shm_t *mln_alloc_shm_new(mln_alloc_t *pool, mln_size_t size, int is_large) -{ - int n, i, j; - mln_alloc_shm_t *shm, *tmp; - mln_u8ptr_t p = pool->mem + sizeof(mln_alloc_t); - - for (tmp = pool->shm_head; tmp != NULL; tmp = tmp->next) { - if ((mln_u8ptr_t)(tmp->addr) - p >= size) break; - p = tmp->addr + tmp->size; - } - if (tmp == NULL && (mln_u8ptr_t)(pool->mem + pool->shm_size) - p < size) { - return NULL; - } - - shm = (mln_alloc_shm_t *)p; - shm->pool = pool; - shm->addr = p; - shm->size = size; - shm->nfree = is_large ? 1: (size / M_ALLOC_SHM_BIT_SIZE); - shm->base = shm->nfree; - shm->large = is_large; - shm->prev = shm->next = NULL; - if (tmp == NULL) { - mln_alloc_shm_chain_add(&pool->shm_head, &pool->shm_tail, shm); - } else { - if (tmp == pool->shm_head) { - shm->next = tmp; - shm->prev = NULL; - tmp->prev = shm; - pool->shm_head = shm; - } else { - shm->next = tmp; - shm->prev = tmp->prev; - tmp->prev->next = shm; - tmp->prev = shm; - } - } - - if (!is_large) { - memset(shm->bitmap, 0, M_ALLOC_SHM_BITMAP_LEN); - n = (sizeof(mln_alloc_shm_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; - shm->nfree -= n; - shm->base -= n; - for (i = 0, j = 0; n > 0; --n) { - shm->bitmap[i] |= (1 << (7-j)); - if (++j >= 8) { - j = 0; - ++i; - } - } - } - - return shm; -} - -static inline mln_alloc_t *mln_alloc_shm_init(mln_size_t size, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock) -{ - mln_alloc_t *pool; -#if defined(MSVC) - HANDLE handle; -#endif - - if (size < M_ALLOC_SHM_DEFAULT_SIZE+1024 || locker == NULL || lock == NULL || unlock == NULL) - return NULL; - -#if defined(MSVC) - if ((handle = CreateFileMapping(INVALID_HANDLE_VALUE, - NULL, - PAGE_READWRITE, -#if defined(__x86_64) - (u_long) (size >> 32), -#else - 0, -#endif - (u_long) (size & 0xffffffff), - NULL)) == NULL) - { - return NULL; - } - pool = (mln_alloc_t *)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0); - if (pool == NULL) { - CloseHandle(handle); - return NULL; - } - pool->map_handle = handle; -#else - -#if defined(MLN_MMAP) -#if defined(MLN_C99) - int fd = open("/dev/zero", O_RDWR); - if (fd < 0) return NULL; - pool = (mln_alloc_t *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - close(fd); -#else - pool = (mln_alloc_t *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); -#endif - if (pool == NULL) return NULL; -#else - return NULL; -#endif -#endif - pool->parent = NULL; - pool->large_used_head = pool->large_used_tail = NULL; - pool->shm_head = pool->shm_tail = NULL; -#if defined(MSVC) - pool->mem = (mln_u8ptr_t)pool; -#else - pool->mem = pool; -#endif - pool->shm_size = size; - pool->locker = locker; - pool->lock = lock; - pool->unlock = unlock; - return pool; -} - -static inline mln_alloc_t *mln_alloc_init(mln_alloc_t *parent) -{ - mln_alloc_t *pool; - -#ifdef __DEBUG__ - (void)mln_blk_chain_add; - (void)mln_blk_chain_del; - (void)mln_chunk_chain_add; - (void)mln_alloc_get_mgr_by_size; - (void)mln_alloc_shm_m; - (void)mln_alloc_free_shm; -#endif - - if (parent != NULL) { - if (mln_alloc_is_shm(parent)) { - if (parent->lock(parent->locker) != 0) return NULL; - } - pool = (mln_alloc_t *)mln_alloc_m(parent, sizeof(mln_alloc_t)); - if (mln_alloc_is_shm(parent)) { - (void)parent->unlock(parent->locker); - } - } else { - pool = (mln_alloc_t *)malloc(sizeof(mln_alloc_t)); - } - if (pool == NULL) return pool; - mln_alloc_mgr_table_init(pool->mgr_tbl); - pool->parent = parent; - pool->large_used_head = pool->large_used_tail = NULL; - pool->shm_head = pool->shm_tail = NULL; - pool->mem = NULL; - pool->shm_size = 0; - pool->locker = NULL; - pool->lock = NULL; - pool->unlock = NULL; - return pool; -} - -MLN_FUNC_VOID(static inline, void, mln_alloc_mgr_table_init, (mln_alloc_mgr_t *tbl), (tbl), { - int i, j; - mln_size_t blk_size; - mln_alloc_mgr_t *am, *amprev; - for (i = 0; i < M_ALLOC_MGR_LEN; i += M_ALLOC_MGR_GRAIN_SIZE) { - blk_size = 0; - for (j = 0; j < i/M_ALLOC_MGR_GRAIN_SIZE + M_ALLOC_BEGIN_OFF; ++j) { - blk_size |= (((mln_size_t)1) << j); - } - am = &tbl[i]; - am->free_head = am->free_tail = NULL; - am->used_head = am->used_tail = NULL; - am->chunk_head = am->chunk_tail = NULL; - am->blk_size = blk_size + 1; - if (i != 0) { - amprev = &tbl[i-1]; - amprev->free_head = amprev->free_tail = NULL; - amprev->used_head = amprev->used_tail = NULL; - amprev->chunk_head = amprev->chunk_tail = NULL; - amprev->blk_size = (am->blk_size + tbl[i-2].blk_size) >> 1; - } - } -}) - -static inline void mln_alloc_destroy(mln_alloc_t *pool) -{ - if (pool == NULL) return; - - mln_alloc_t *parent = pool->parent; - if (parent != NULL && mln_alloc_is_shm(parent)) - if (parent->lock(parent->locker) != 0) - return; - if (pool->mem == NULL) { - mln_alloc_mgr_t *am, *amend; - amend = pool->mgr_tbl + M_ALLOC_MGR_LEN; - mln_alloc_chunk_t *ch; - for (am = pool->mgr_tbl; am < amend; ++am) { - while ((ch = am->chunk_head) != NULL) { - mln_chunk_chain_del(&(am->chunk_head), &(am->chunk_tail), ch); - if (parent != NULL) mln_alloc_free(ch); - else free(ch); - } - } - while ((ch = pool->large_used_head) != NULL) { - mln_chunk_chain_del(&(pool->large_used_head), &(pool->large_used_tail), ch); - if (parent != NULL) mln_alloc_free(ch); - else free(ch); - } - if (parent != NULL) mln_alloc_free(pool); - else free(pool); - } else { -#if defined(MSVC) - HANDLE handle = pool->map_handle; - UnmapViewOfFile(pool->mem); - CloseHandle(handle); -#else -#if defined(MLN_MMAP) - munmap(pool->mem, pool->shm_size); -#endif -#endif - } - if (parent != NULL && mln_alloc_is_shm(parent)) - (void)parent->unlock(parent->locker); -} - -static inline void *mln_alloc_m(mln_alloc_t *pool, mln_size_t size) -{ -#ifdef __DEBUG__ - return malloc(size); -#else - mln_alloc_blk_t *blk; - mln_alloc_mgr_t *am; - mln_alloc_chunk_t *ch; - mln_u8ptr_t ptr; - mln_size_t n; - - if (pool->mem != NULL) { - return mln_alloc_shm_m(pool, size); - } - - am = mln_alloc_get_mgr_by_size(pool->mgr_tbl, size); - - if (am == NULL) { - n = (size + sizeof(mln_alloc_blk_t) + sizeof(mln_alloc_chunk_t) + 3) >> 2; - size = n << 2; - if (pool->parent != NULL) { - if (mln_alloc_is_shm(pool->parent)) { - if (pool->parent->lock(pool->parent->locker) != 0) - return NULL; - } - ptr = (mln_u8ptr_t)mln_alloc_c(pool->parent, size); - if (mln_alloc_is_shm(pool->parent)) { - (void)pool->parent->unlock(pool->parent->locker); - } - } else { - ptr = (mln_u8ptr_t)calloc(1, size); - } - if (ptr == NULL) return NULL; - ch = (mln_alloc_chunk_t *)ptr; - ch->refer = 1; - mln_chunk_chain_add(&(pool->large_used_head), &(pool->large_used_tail), ch); - blk = (mln_alloc_blk_t *)(ptr + sizeof(mln_alloc_chunk_t)); - blk->data = ptr + sizeof(mln_alloc_chunk_t) + sizeof(mln_alloc_blk_t); - blk->chunk = ch; - blk->pool = pool; - blk->blk_size = size - (sizeof(mln_alloc_chunk_t) + sizeof(mln_alloc_blk_t)); - blk->is_large = 1; - blk->in_used = 1; - ch->blks[0] = blk; - return blk->data; - } - - if (am->free_head == NULL) { - n = (sizeof(mln_alloc_blk_t) + am->blk_size + 3) >> 2; - size = n << 2; - - n = (sizeof(mln_alloc_chunk_t) + M_ALLOC_BLK_NUM * size + 3) >> 2; - - if (pool->parent != NULL) { - if (mln_alloc_is_shm(pool->parent)) { - if (pool->parent->lock(pool->parent->locker) != 0) - return NULL; - } - ptr = (mln_u8ptr_t)mln_alloc_m(pool->parent, n << 2); - if (mln_alloc_is_shm(pool->parent)) { - (void)pool->parent->unlock(pool->parent->locker); - } - } else { - ptr = (mln_u8ptr_t)malloc(n << 2); - } - if (ptr == NULL) { - for (; am < pool->mgr_tbl + M_ALLOC_MGR_LEN; ++am) { - if (am->free_head != NULL) goto out; - } - return NULL; - } - ch = (mln_alloc_chunk_t *)ptr; - mln_chunk_chain_add(&(am->chunk_head), &(am->chunk_tail), ch); - ch->refer = ch->count = 0; - ch->mgr = am; - ptr += sizeof(mln_alloc_chunk_t); - for (n = 0; n < M_ALLOC_BLK_NUM; ++n) { - blk = (mln_alloc_blk_t *)ptr; - mln_blk_chain_add(&(am->free_head), &(am->free_tail), blk); - blk->pool = pool; - blk->data = ptr + sizeof(mln_alloc_blk_t); - blk->chunk = ch; - blk->blk_size = am->blk_size; - blk->is_large = blk->in_used = 0; - ch->blks[n] = blk; - ptr += size; - } - ch->blks[n] = NULL; - } - -out: - blk = am->free_tail; - mln_blk_chain_del(&(am->free_head), &(am->free_tail), blk); - mln_blk_chain_add(&(am->used_head), &(am->used_tail), blk); - blk->in_used = 1; - ++(blk->chunk->refer); - return blk->data; -#endif -} - -static inline mln_alloc_mgr_t *mln_alloc_get_mgr_by_size(mln_alloc_mgr_t *tbl, mln_size_t size) -{ - if (size > tbl[M_ALLOC_MGR_LEN-1].blk_size) - return NULL; - if (size <= tbl[0].blk_size) return &tbl[0]; - - mln_alloc_mgr_t *am = tbl; -#if defined(i386) || defined(__x86_64) - register mln_size_t off = 0; - __asm__("bsr %1, %0":"=r"(off):"m"(size)); -#else - mln_size_t off = 0; - int i; - for (i = (sizeof(mln_size_t)<<3) - 1; i >= 0; --i) { - if (size & (((mln_size_t)1) << i)) { - off = i; - break; - } - } -#endif - off = (off - M_ALLOC_BEGIN_OFF) * M_ALLOC_MGR_GRAIN_SIZE; - if (am[off].blk_size >= size) return &am[off]; - if (am[off+1].blk_size >= size) return &am[off+1]; - return &am[off+2]; -} - -static inline void *mln_alloc_c(mln_alloc_t *pool, mln_size_t size) -{ -#ifdef __DEBUG__ - return calloc(1, size); -#else - mln_u8ptr_t ptr = mln_alloc_m(pool, size); - if (ptr == NULL) return NULL; - memset(ptr, 0, size); - return ptr; -#endif -} - -static void *mln_alloc_re(mln_alloc_t *pool, void *ptr, mln_size_t size) -{ -#ifdef __DEBUG__ - return realloc(ptr, size); -#else - if (size == 0) { - mln_alloc_free(ptr); - return NULL; - } - - mln_alloc_blk_t *old_blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); - if (old_blk->pool == pool && old_blk->blk_size >= size) { - return ptr; - } - - mln_u8ptr_t new_ptr = mln_alloc_m(pool, size); - if (new_ptr == NULL) return NULL; - memcpy(new_ptr, ptr, old_blk->blk_size); - mln_alloc_free(ptr); - - return new_ptr; -#endif -} - -static inline void mln_alloc_free(void *ptr) -{ - if (ptr == NULL) { - return; - } -#ifdef __DEBUG__ - return free(ptr); -#else - - mln_alloc_t *pool; - mln_alloc_chunk_t *ch; - mln_alloc_mgr_t *am; - mln_alloc_blk_t *blk; - - blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); - - ASSERT(blk->in_used); - - pool = blk->pool; - if (pool->mem) { - mln_alloc_free_shm(ptr); - return; - } - - if (blk->is_large) { - mln_chunk_chain_del(&(pool->large_used_head), &(pool->large_used_tail), blk->chunk); - if (pool->parent != NULL) { - if (mln_alloc_is_shm(pool->parent)) { - if (pool->parent->lock(pool->parent->locker) != 0) { - return; - } - } - mln_alloc_free(blk->chunk); - if (mln_alloc_is_shm(pool->parent)) { - (void)pool->parent->unlock(pool->parent->locker); - } - } else - free(blk->chunk); - return; - } - ch = blk->chunk; - am = ch->mgr; - blk->in_used = 0; - mln_blk_chain_del(&(am->used_head), &(am->used_tail), blk); - mln_blk_chain_add(&(am->free_head), &(am->free_tail), blk); - if (!--(ch->refer) && ++(ch->count) > M_ALLOC_CHUNK_COUNT) { - mln_alloc_blk_t **blks = ch->blks; - while (*blks != NULL) { - mln_blk_chain_del(&(am->free_head), &(am->free_tail), *(blks++)); - } - mln_chunk_chain_del(&(am->chunk_head), &(am->chunk_tail), ch); - if (pool->parent != NULL) { - if (mln_alloc_is_shm(pool->parent)) { - if (pool->parent->lock(pool->parent->locker) != 0) { - return; - } - } - mln_alloc_free(ch); - if (mln_alloc_is_shm(pool->parent)) { - (void)pool->parent->unlock(pool->parent->locker); - } - } else - free(ch); - } -#endif -} - -MLN_FUNC(static inline, void *, mln_alloc_shm_m, (mln_alloc_t *pool, mln_size_t size), (pool, size), { - mln_alloc_shm_t *as; - mln_off_t Boff = -1, boff = -1; - - if (size > M_ALLOC_SHM_LARGE_SIZE) { - return mln_alloc_shm_large_m(pool, size); - } - - if (pool->shm_head == NULL) { -new_block: - as = mln_alloc_shm_new_block(pool, &Boff, &boff, size); - if (as == NULL) { - return NULL; - } - } else { - for (as = pool->shm_head; as != NULL; as = as->next) { - if (mln_alloc_shm_allowed(as, &Boff, &boff, size)) { - break; - } - } - if (as == NULL) goto new_block; - } - return mln_alloc_shm_set_bitmap(as, Boff, boff, size); -}) - -static inline void *mln_alloc_shm_large_m(mln_alloc_t *pool, mln_size_t size) -{ - mln_alloc_shm_t *as; - mln_alloc_blk_t *blk; - - if ((as = mln_alloc_shm_new(pool, size + sizeof(mln_alloc_shm_t)+sizeof(mln_alloc_blk_t), 1)) == NULL) - return NULL; - as->nfree = 0; - blk = (mln_alloc_blk_t *)(as->addr+sizeof(mln_alloc_shm_t)); - memset(blk, 0, sizeof(mln_alloc_blk_t)); - blk->pool = pool; - blk->blk_size = size; - blk->data = as->addr + sizeof(mln_alloc_shm_t) + sizeof(mln_alloc_blk_t); - blk->chunk = (mln_alloc_chunk_t *)as; - blk->is_large = 1; - blk->in_used = 1; - return blk->data; -} - -MLN_FUNC(static inline, mln_alloc_shm_t *, mln_alloc_shm_new_block, \ - (mln_alloc_t *pool, mln_off_t *Boff, mln_off_t *boff, mln_size_t size), \ - (pool, Boff, boff, size), \ -{ - mln_alloc_shm_t *ret; - if ((ret = mln_alloc_shm_new(pool, M_ALLOC_SHM_DEFAULT_SIZE, 0)) == NULL) { - return NULL; - } - mln_alloc_shm_allowed(ret, Boff, boff, size); - return ret; -}) - -MLN_FUNC(static inline, int, mln_alloc_shm_allowed, \ - (mln_alloc_shm_t *as, mln_off_t *Boff, mln_off_t *boff, mln_size_t size), \ - (as, Boff, boff, size), \ -{ - int i, j = -1, s = -1; - int n = (size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; - mln_u8ptr_t p, pend, save = NULL; - - if (n > as->nfree) return 0; - - p = as->bitmap; - for (pend = p + M_ALLOC_SHM_BITMAP_LEN; p < pend; ++p) { - if ((*p & 0xff) == 0xff) { - if (save != NULL) { - j = -1; - s = -1; - save = NULL; - } - continue; - } - - for (i = 7; i >= 0; --i) { - if (!(*p & ((mln_u8_t)1 << i))) { - if (save == NULL) { - j = n; - s = i; - save = p; - } - if (--j <= 0) { - break; - } - } else if (save != NULL) { - j = -1; - s = -1; - save = NULL; - } - } - - if (save != NULL && !j) { - *Boff = save - as->bitmap; - *boff = s; - return 1; - } - } - return 0; -}) - -MLN_FUNC(static inline, void *, mln_alloc_shm_set_bitmap, \ - (mln_alloc_shm_t *as, mln_off_t Boff, mln_off_t boff, mln_size_t size), \ - (as, Boff, boff, size), \ -{ - int i, n = (size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; - mln_u8ptr_t p, pend, addr; - mln_alloc_blk_t *blk; - - addr = as->addr + (Boff * 8 + (7 - boff)) * M_ALLOC_SHM_BIT_SIZE; - blk = (mln_alloc_blk_t *)addr; - memset(blk, 0, sizeof(mln_alloc_blk_t)); - blk->pool = as->pool; - blk->data = addr + sizeof(mln_alloc_blk_t); - blk->chunk = (mln_alloc_chunk_t *)as; - blk->blk_size = size; - blk->padding = ((Boff & 0xffff) << 8) | (boff & 0xff); - blk->is_large = 0; - blk->in_used = 1; - p = as->bitmap + Boff; - pend = p + M_ALLOC_SHM_BITMAP_LEN; - for (i = boff; p < pend;) { - *p |= ((mln_u8_t)1 << i); - --as->nfree; - if (--n <= 0) break; - if (--i < 0) { - i = 7; - ++p; - } - } - - return blk->data; -}) - -MLN_FUNC_VOID(static inline, void, mln_alloc_free_shm, (void *ptr), (ptr), { - mln_alloc_blk_t *blk; - mln_alloc_shm_t *as; - mln_off_t Boff, boff; - mln_u8ptr_t p, pend; - int i, n; - - blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); - as = (mln_alloc_shm_t *)(blk->chunk); - if (!as->large) { - Boff = (blk->padding >> 8) & 0xffff; - boff = blk->padding & 0xff; - blk->in_used = 0; - p = as->bitmap + Boff; - n = (blk->blk_size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; - i = boff; - for (pend = as->bitmap+M_ALLOC_SHM_BITMAP_LEN; p < pend;) { - *p &= (~((mln_u8_t)1 << i)); - ++as->nfree; - if (--n <= 0) break; - if (--i < 0) { - i = 7; - ++p; - } - } - } - if (as->large || as->nfree == as->base) { - mln_alloc_shm_chain_del(&as->pool->shm_head, &as->pool->shm_tail, as); - } -}) - -/* - * chain - */ -MLN_CHAIN_FUNC_DEFINE(static inline, \ - mln_blk, \ - mln_alloc_blk_t, \ - prev, \ - next); -MLN_CHAIN_FUNC_DEFINE(static inline, \ - mln_chunk, \ - mln_alloc_chunk_t, \ - prev, \ - next); -MLN_CHAIN_FUNC_DEFINE(static inline, \ - mln_alloc_shm, \ - mln_alloc_shm_t, \ - prev, \ - next); +mln_alloc_t *mln_alloc_shm_init(mln_size_t capacity, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock); +mln_alloc_t *mln_alloc_init(mln_alloc_t *parent, mln_size_t capacity); +void mln_alloc_destroy(mln_alloc_t *pool); +void *mln_alloc_m(mln_alloc_t *pool, mln_size_t size); +void *mln_alloc_c(mln_alloc_t *pool, mln_size_t size); +void *mln_alloc_re(mln_alloc_t *pool, void *ptr, mln_size_t size); +void mln_alloc_free(void *ptr); +mln_size_t mln_alloc_available_capacity(mln_alloc_t *pool); #endif diff --git a/include/mln_parser_generator.h b/include/mln_parser_generator.h index 1cd94fcb..89a822d2 100644 --- a/include/mln_parser_generator.h +++ b/include/mln_parser_generator.h @@ -579,7 +579,7 @@ MLN_FUNC(SCOPE, int, PREFIX_NAME##_preprocess, (struct PREFIX_NAME##_preprocess_ mln_string_t tmp;\ mln_production_t *prod = attr->prod_tbl;\ mln_production_t *prodend = attr->prod_tbl + attr->nr_prod;\ - if ((pool = mln_alloc_init(NULL)) == NULL) {\ + if ((pool = mln_alloc_init(NULL, 0)) == NULL) {\ mln_log(error, "No memory.\n");\ goto err2;\ }\ diff --git a/src/mln_alloc.c b/src/mln_alloc.c index f87697e7..3a412957 100644 --- a/src/mln_alloc.c +++ b/src/mln_alloc.c @@ -4,3 +4,721 @@ */ #include "mln_alloc.h" + +MLN_CHAIN_FUNC_DECLARE(static inline, \ + mln_blk, \ + mln_alloc_blk_t, ); +MLN_CHAIN_FUNC_DECLARE(static inline, \ + mln_chunk, \ + mln_alloc_chunk_t, ); +MLN_CHAIN_FUNC_DECLARE(static inline, \ + mln_alloc_shm, \ + mln_alloc_shm_t, ); +static inline void +mln_alloc_mgr_table_init(mln_alloc_mgr_t *tbl); +static inline mln_alloc_mgr_t * +mln_alloc_get_mgr_by_size(mln_alloc_mgr_t *tbl, mln_size_t size); +static inline void *mln_alloc_shm_m(mln_alloc_t *pool, mln_size_t size); +static inline void *mln_alloc_shm_large_m(mln_alloc_t *pool, mln_size_t size); +static inline int mln_alloc_shm_allowed(mln_alloc_shm_t *as, mln_off_t *Boff, mln_off_t *boff, mln_size_t size); +static inline void *mln_alloc_shm_set_bitmap(mln_alloc_shm_t *as, mln_off_t Boff, mln_off_t boff, mln_size_t size); +static inline mln_alloc_shm_t *mln_alloc_shm_new_block(mln_alloc_t *pool, mln_off_t *Boff, mln_off_t *boff, mln_size_t size); +static inline void mln_alloc_free_shm(void *ptr); + +static inline mln_alloc_shm_t *mln_alloc_shm_new(mln_alloc_t *pool, mln_size_t size, int is_large) +{ + int n, i, j; + mln_alloc_shm_t *shm, *tmp; + mln_u8ptr_t p = pool->mem + sizeof(mln_alloc_t); + + for (tmp = pool->shm_head; tmp != NULL; tmp = tmp->next) { + if ((mln_u8ptr_t)(tmp->addr) - p >= size) break; + p = tmp->addr + tmp->size; + } + if (tmp == NULL && (mln_u8ptr_t)(pool->mem + pool->capacity) - p < size) { + return NULL; + } + + shm = (mln_alloc_shm_t *)p; + shm->pool = pool; + shm->addr = p; + shm->size = size; + shm->nfree = is_large ? 1: (size / M_ALLOC_SHM_BIT_SIZE); + shm->base = shm->nfree; + shm->large = is_large; + shm->prev = shm->next = NULL; + if (tmp == NULL) { + mln_alloc_shm_chain_add(&pool->shm_head, &pool->shm_tail, shm); + } else { + if (tmp == pool->shm_head) { + shm->next = tmp; + shm->prev = NULL; + tmp->prev = shm; + pool->shm_head = shm; + } else { + shm->next = tmp; + shm->prev = tmp->prev; + tmp->prev->next = shm; + tmp->prev = shm; + } + } + + if (!is_large) { + memset(shm->bitmap, 0, M_ALLOC_SHM_BITMAP_LEN); + n = (sizeof(mln_alloc_shm_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; + shm->nfree -= n; + shm->base -= n; + for (i = 0, j = 0; n > 0; --n) { + shm->bitmap[i] |= (1 << (7-j)); + if (++j >= 8) { + j = 0; + ++i; + } + } + } + + return shm; +} + +mln_alloc_t *mln_alloc_shm_init(mln_size_t capacity, void *locker, mln_alloc_shm_lock_cb_t lock, mln_alloc_shm_lock_cb_t unlock) +{ + mln_alloc_t *pool; +#if defined(MSVC) + HANDLE handle; +#endif + + if (capacity < M_ALLOC_SHM_DEFAULT_SIZE+1024 || locker == NULL || lock == NULL || unlock == NULL) { + return NULL; + } + +#if defined(MSVC) + if ((handle = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, +#if defined(__x86_64) + (u_long) (capacity >> 32), +#else + 0, +#endif + (u_long) (capacity & 0xffffffff), + NULL)) == NULL) + { + return NULL; + } + pool = (mln_alloc_t *)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0); + if (pool == NULL) { + CloseHandle(handle); + return NULL; + } + pool->map_handle = handle; +#else + +#if defined(MLN_MMAP) +#if defined(MLN_C99) + int fd = open("/dev/zero", O_RDWR); + if (fd < 0) return NULL; + pool = (mln_alloc_t *)mmap(NULL, capacity, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); +#else + pool = (mln_alloc_t *)mmap(NULL, capacity, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); +#endif + if (pool == NULL) return NULL; +#else + return NULL; +#endif +#endif + pool->parent = NULL; + pool->large_used_head = pool->large_used_tail = NULL; + pool->shm_head = pool->shm_tail = NULL; +#if defined(MSVC) + pool->mem = (mln_u8ptr_t)pool; +#else + pool->mem = pool; +#endif + pool->capacity = capacity; + pool->in_used = 0; + pool->locker = locker; + pool->lock = lock; + pool->unlock = unlock; + return pool; +} + +mln_alloc_t *mln_alloc_init(mln_alloc_t *parent, mln_size_t capacity) +{ + mln_alloc_t *pool; + +#ifdef __DEBUG__ + (void)mln_blk_chain_add; + (void)mln_blk_chain_del; + (void)mln_chunk_chain_add; + (void)mln_alloc_get_mgr_by_size; + (void)mln_alloc_shm_m; + (void)mln_alloc_free_shm; +#endif + + if (parent != NULL) { + if (mln_alloc_is_shm(parent)) { + if (parent->lock(parent->locker) != 0) return NULL; + } + pool = (mln_alloc_t *)mln_alloc_m(parent, sizeof(mln_alloc_t)); + if (mln_alloc_is_shm(parent)) { + (void)parent->unlock(parent->locker); + } + } else { + pool = (mln_alloc_t *)malloc(sizeof(mln_alloc_t)); + } + if (pool == NULL) return pool; + mln_alloc_mgr_table_init(pool->mgr_tbl); + pool->parent = parent; + pool->large_used_head = pool->large_used_tail = NULL; + pool->shm_head = pool->shm_tail = NULL; + pool->mem = NULL; + pool->capacity = capacity; + pool->in_used = 0; + pool->locker = NULL; + pool->lock = NULL; + pool->unlock = NULL; + return pool; +} + +MLN_FUNC_VOID(static inline, void, mln_alloc_mgr_table_init, (mln_alloc_mgr_t *tbl), (tbl), { + int i, j; + mln_size_t blk_size; + mln_alloc_mgr_t *am, *amprev; + for (i = 0; i < M_ALLOC_MGR_LEN; i += M_ALLOC_MGR_GRAIN_SIZE) { + blk_size = 0; + for (j = 0; j < i/M_ALLOC_MGR_GRAIN_SIZE + M_ALLOC_BEGIN_OFF; ++j) { + blk_size |= (((mln_size_t)1) << j); + } + am = &tbl[i]; + am->free_head = am->free_tail = NULL; + am->used_head = am->used_tail = NULL; + am->chunk_head = am->chunk_tail = NULL; + am->blk_size = blk_size + 1; + if (i != 0) { + amprev = &tbl[i-1]; + amprev->free_head = amprev->free_tail = NULL; + amprev->used_head = amprev->used_tail = NULL; + amprev->chunk_head = amprev->chunk_tail = NULL; + amprev->blk_size = (am->blk_size + tbl[i-2].blk_size) >> 1; + } + } +}) + +void mln_alloc_destroy(mln_alloc_t *pool) +{ + if (pool == NULL) return; + + mln_alloc_t *parent = pool->parent; + if (parent != NULL && mln_alloc_is_shm(parent)) + if (parent->lock(parent->locker) != 0) + return; + if (pool->mem == NULL) { + mln_alloc_mgr_t *am, *amend; + amend = pool->mgr_tbl + M_ALLOC_MGR_LEN; + mln_alloc_chunk_t *ch; + for (am = pool->mgr_tbl; am < amend; ++am) { + while ((ch = am->chunk_head) != NULL) { + mln_chunk_chain_del(&(am->chunk_head), &(am->chunk_tail), ch); + if (parent != NULL) mln_alloc_free(ch); + else free(ch); + } + } + while ((ch = pool->large_used_head) != NULL) { + mln_chunk_chain_del(&(pool->large_used_head), &(pool->large_used_tail), ch); + if (parent != NULL) mln_alloc_free(ch); + else free(ch); + } + if (parent != NULL) mln_alloc_free(pool); + else free(pool); + } else { +#if defined(MSVC) + HANDLE handle = pool->map_handle; + UnmapViewOfFile(pool->mem); + CloseHandle(handle); +#else +#if defined(MLN_MMAP) + munmap(pool->mem, pool->capacity); +#endif +#endif + } + if (parent != NULL && mln_alloc_is_shm(parent)) + (void)parent->unlock(parent->locker); +} + +void *mln_alloc_m(mln_alloc_t *pool, mln_size_t size) +{ +#ifdef __DEBUG__ + return malloc(size); +#else + mln_alloc_blk_t *blk; + mln_alloc_mgr_t *am; + mln_alloc_chunk_t *ch; + mln_u8ptr_t ptr; + mln_size_t n, alloc_size; + + if (pool->mem != NULL) { + return mln_alloc_shm_m(pool, size); + } + + am = mln_alloc_get_mgr_by_size(pool->mgr_tbl, size); + + if (am == NULL) { + n = (size + sizeof(mln_alloc_blk_t) + sizeof(mln_alloc_chunk_t) + 3) >> 2; + size = n << 2; + + if (pool->capacity) { + if (size + pool->in_used > pool->capacity) + return NULL; + + pool->in_used += size; + } + + if (pool->parent != NULL) { + if (mln_alloc_is_shm(pool->parent)) { + if (pool->parent->lock(pool->parent->locker) != 0) + return NULL; + } + ptr = (mln_u8ptr_t)mln_alloc_c(pool->parent, size); + if (mln_alloc_is_shm(pool->parent)) { + (void)pool->parent->unlock(pool->parent->locker); + } + } else { + ptr = (mln_u8ptr_t)calloc(1, size); + } + if (ptr == NULL) return NULL; + ch = (mln_alloc_chunk_t *)ptr; + ch->refer = 1; + ch->size = size; + mln_chunk_chain_add(&(pool->large_used_head), &(pool->large_used_tail), ch); + blk = (mln_alloc_blk_t *)(ptr + sizeof(mln_alloc_chunk_t)); + blk->data = ptr + sizeof(mln_alloc_chunk_t) + sizeof(mln_alloc_blk_t); + blk->chunk = ch; + blk->pool = pool; + blk->blk_size = size - (sizeof(mln_alloc_chunk_t) + sizeof(mln_alloc_blk_t)); + blk->is_large = 1; + blk->in_used = 1; + ch->blks[0] = blk; + return blk->data; + } + + if (am->free_head == NULL) { + n = (sizeof(mln_alloc_blk_t) + am->blk_size + 3) >> 2; + size = n << 2; + + n = (sizeof(mln_alloc_chunk_t) + M_ALLOC_BLK_NUM * size + 3) >> 2; + alloc_size = n << 2; + + if (pool->capacity) { + if (alloc_size + pool->in_used > pool->capacity) { + goto oom; + } + + pool->in_used += alloc_size; + } + + if (pool->parent != NULL) { + if (mln_alloc_is_shm(pool->parent)) { + if (pool->parent->lock(pool->parent->locker) != 0) + return NULL; + } + ptr = (mln_u8ptr_t)mln_alloc_m(pool->parent, alloc_size); + if (mln_alloc_is_shm(pool->parent)) { + (void)pool->parent->unlock(pool->parent->locker); + } + } else { + ptr = (mln_u8ptr_t)malloc(alloc_size); + } + if (ptr == NULL) { +oom: + for (; am < pool->mgr_tbl + M_ALLOC_MGR_LEN; ++am) { + if (am->free_head != NULL) goto out; + } + return NULL; + } + ch = (mln_alloc_chunk_t *)ptr; + mln_chunk_chain_add(&(am->chunk_head), &(am->chunk_tail), ch); + ch->refer = ch->count = 0; + ch->mgr = am; + ch->size = alloc_size; + ptr += sizeof(mln_alloc_chunk_t); + for (n = 0; n < M_ALLOC_BLK_NUM; ++n) { + blk = (mln_alloc_blk_t *)ptr; + mln_blk_chain_add(&(am->free_head), &(am->free_tail), blk); + blk->pool = pool; + blk->data = ptr + sizeof(mln_alloc_blk_t); + blk->chunk = ch; + blk->blk_size = am->blk_size; + blk->is_large = blk->in_used = 0; + ch->blks[n] = blk; + ptr += size; + } + ch->blks[n] = NULL; + } + +out: + blk = am->free_tail; + mln_blk_chain_del(&(am->free_head), &(am->free_tail), blk); + mln_blk_chain_add(&(am->used_head), &(am->used_tail), blk); + blk->in_used = 1; + ++(blk->chunk->refer); + return blk->data; +#endif +} + +static inline mln_alloc_mgr_t *mln_alloc_get_mgr_by_size(mln_alloc_mgr_t *tbl, mln_size_t size) +{ + if (size > tbl[M_ALLOC_MGR_LEN-1].blk_size) + return NULL; + if (size <= tbl[0].blk_size) return &tbl[0]; + + mln_alloc_mgr_t *am = tbl; +#if defined(i386) || defined(__x86_64) + register mln_size_t off = 0; + __asm__("bsr %1, %0":"=r"(off):"m"(size)); +#else + mln_size_t off = 0; + int i; + for (i = (sizeof(mln_size_t)<<3) - 1; i >= 0; --i) { + if (size & (((mln_size_t)1) << i)) { + off = i; + break; + } + } +#endif + off = (off - M_ALLOC_BEGIN_OFF) * M_ALLOC_MGR_GRAIN_SIZE; + if (am[off].blk_size >= size) return &am[off]; + if (am[off+1].blk_size >= size) return &am[off+1]; + return &am[off+2]; +} + +void *mln_alloc_c(mln_alloc_t *pool, mln_size_t size) +{ +#ifdef __DEBUG__ + return calloc(1, size); +#else + mln_u8ptr_t ptr = mln_alloc_m(pool, size); + if (ptr == NULL) return NULL; + memset(ptr, 0, size); + return ptr; +#endif +} + +void *mln_alloc_re(mln_alloc_t *pool, void *ptr, mln_size_t size) +{ +#ifdef __DEBUG__ + return realloc(ptr, size); +#else + if (size == 0) { + mln_alloc_free(ptr); + return NULL; + } + + mln_alloc_blk_t *old_blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); + if (old_blk->pool == pool && old_blk->blk_size >= size) { + return ptr; + } + + mln_u8ptr_t new_ptr = mln_alloc_m(pool, size); + if (new_ptr == NULL) return NULL; + memcpy(new_ptr, ptr, old_blk->blk_size); + mln_alloc_free(ptr); + + return new_ptr; +#endif +} + +void mln_alloc_free(void *ptr) +{ + if (ptr == NULL) { + return; + } +#ifdef __DEBUG__ + return free(ptr); +#else + + mln_alloc_t *pool; + mln_alloc_chunk_t *ch; + mln_alloc_mgr_t *am; + mln_alloc_blk_t *blk; + mln_size_t size; + + blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); + size = blk->chunk->size; + + ASSERT(blk->in_used); + + pool = blk->pool; + if (pool->mem) { + mln_alloc_free_shm(ptr); + return; + } + + if (blk->is_large) { + mln_chunk_chain_del(&(pool->large_used_head), &(pool->large_used_tail), blk->chunk); + if (pool->parent != NULL) { + if (mln_alloc_is_shm(pool->parent)) { + if (pool->parent->lock(pool->parent->locker) != 0) { + return; + } + } + mln_alloc_free(blk->chunk); + if (mln_alloc_is_shm(pool->parent)) { + (void)pool->parent->unlock(pool->parent->locker); + } + } else { + free(blk->chunk); + } + + if (pool->capacity) { + ASSERT(pool->in_used >= size); + pool->in_used -= size; + } + return; + } + ch = blk->chunk; + am = ch->mgr; + blk->in_used = 0; + mln_blk_chain_del(&(am->used_head), &(am->used_tail), blk); + mln_blk_chain_add(&(am->free_head), &(am->free_tail), blk); + if (!--(ch->refer) && ++(ch->count) > M_ALLOC_CHUNK_COUNT) { + mln_alloc_blk_t **blks = ch->blks; + while (*blks != NULL) { + mln_blk_chain_del(&(am->free_head), &(am->free_tail), *(blks++)); + } + mln_chunk_chain_del(&(am->chunk_head), &(am->chunk_tail), ch); + if (pool->parent != NULL) { + if (mln_alloc_is_shm(pool->parent)) { + if (pool->parent->lock(pool->parent->locker) != 0) { + return; + } + } + mln_alloc_free(ch); + if (mln_alloc_is_shm(pool->parent)) { + (void)pool->parent->unlock(pool->parent->locker); + } + } else { + free(ch); + } + + if (pool->capacity) { + ASSERT(pool->in_used >= size); + pool->in_used -= size; + } + } +#endif +} + +MLN_FUNC(static inline, void *, mln_alloc_shm_m, (mln_alloc_t *pool, mln_size_t size), (pool, size), { + mln_alloc_shm_t *as; + mln_off_t Boff = -1, boff = -1; + + if (size > M_ALLOC_SHM_LARGE_SIZE) { + return mln_alloc_shm_large_m(pool, size); + } + + if (pool->shm_head == NULL) { +new_block: + as = mln_alloc_shm_new_block(pool, &Boff, &boff, size); + if (as == NULL) { + return NULL; + } + } else { + for (as = pool->shm_head; as != NULL; as = as->next) { + if (mln_alloc_shm_allowed(as, &Boff, &boff, size)) { + break; + } + } + if (as == NULL) goto new_block; + } + return mln_alloc_shm_set_bitmap(as, Boff, boff, size); +}) + +static inline void *mln_alloc_shm_large_m(mln_alloc_t *pool, mln_size_t size) +{ + mln_alloc_shm_t *as; + mln_alloc_blk_t *blk; + + if ((as = mln_alloc_shm_new(pool, size + sizeof(mln_alloc_shm_t)+sizeof(mln_alloc_blk_t), 1)) == NULL) + return NULL; + as->nfree = 0; + blk = (mln_alloc_blk_t *)(as->addr+sizeof(mln_alloc_shm_t)); + memset(blk, 0, sizeof(mln_alloc_blk_t)); + blk->pool = pool; + blk->blk_size = size; + blk->data = as->addr + sizeof(mln_alloc_shm_t) + sizeof(mln_alloc_blk_t); + blk->chunk = (mln_alloc_chunk_t *)as; + blk->is_large = 1; + blk->in_used = 1; + return blk->data; +} + +MLN_FUNC(static inline, mln_alloc_shm_t *, mln_alloc_shm_new_block, \ + (mln_alloc_t *pool, mln_off_t *Boff, mln_off_t *boff, mln_size_t size), \ + (pool, Boff, boff, size), \ +{ + mln_alloc_shm_t *ret; + if ((ret = mln_alloc_shm_new(pool, M_ALLOC_SHM_DEFAULT_SIZE, 0)) == NULL) { + return NULL; + } + mln_alloc_shm_allowed(ret, Boff, boff, size); + return ret; +}) + +MLN_FUNC(static inline, int, mln_alloc_shm_allowed, \ + (mln_alloc_shm_t *as, mln_off_t *Boff, mln_off_t *boff, mln_size_t size), \ + (as, Boff, boff, size), \ +{ + int i, j = -1, s = -1; + int n = (size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; + mln_u8ptr_t p, pend, save = NULL; + + if (n > as->nfree) return 0; + + p = as->bitmap; + for (pend = p + M_ALLOC_SHM_BITMAP_LEN; p < pend; ++p) { + if ((*p & 0xff) == 0xff) { + if (save != NULL) { + j = -1; + s = -1; + save = NULL; + } + continue; + } + + for (i = 7; i >= 0; --i) { + if (!(*p & ((mln_u8_t)1 << i))) { + if (save == NULL) { + j = n; + s = i; + save = p; + } + if (--j <= 0) { + break; + } + } else if (save != NULL) { + j = -1; + s = -1; + save = NULL; + } + } + + if (save != NULL && !j) { + *Boff = save - as->bitmap; + *boff = s; + return 1; + } + } + return 0; +}) + +MLN_FUNC(static inline, void *, mln_alloc_shm_set_bitmap, \ + (mln_alloc_shm_t *as, mln_off_t Boff, mln_off_t boff, mln_size_t size), \ + (as, Boff, boff, size), \ +{ + int i, n = (size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; + mln_u8ptr_t p, pend, addr; + mln_alloc_blk_t *blk; + + addr = as->addr + (Boff * 8 + (7 - boff)) * M_ALLOC_SHM_BIT_SIZE; + blk = (mln_alloc_blk_t *)addr; + memset(blk, 0, sizeof(mln_alloc_blk_t)); + blk->pool = as->pool; + blk->data = addr + sizeof(mln_alloc_blk_t); + blk->chunk = (mln_alloc_chunk_t *)as; + blk->blk_size = size; + blk->padding = ((Boff & 0xffff) << 8) | (boff & 0xff); + blk->is_large = 0; + blk->in_used = 1; + p = as->bitmap + Boff; + pend = p + M_ALLOC_SHM_BITMAP_LEN; + for (i = boff; p < pend;) { + *p |= ((mln_u8_t)1 << i); + --as->nfree; + if (--n <= 0) break; + if (--i < 0) { + i = 7; + ++p; + } + } + + return blk->data; +}) + +MLN_FUNC_VOID(static inline, void, mln_alloc_free_shm, (void *ptr), (ptr), { + mln_alloc_blk_t *blk; + mln_alloc_shm_t *as; + mln_off_t Boff, boff; + mln_u8ptr_t p, pend; + int i, n; + + blk = (mln_alloc_blk_t *)((mln_u8ptr_t)ptr - sizeof(mln_alloc_blk_t)); + as = (mln_alloc_shm_t *)(blk->chunk); + if (!as->large) { + Boff = (blk->padding >> 8) & 0xffff; + boff = blk->padding & 0xff; + blk->in_used = 0; + p = as->bitmap + Boff; + n = (blk->blk_size+sizeof(mln_alloc_blk_t)+M_ALLOC_SHM_BIT_SIZE-1) / M_ALLOC_SHM_BIT_SIZE; + i = boff; + for (pend = as->bitmap+M_ALLOC_SHM_BITMAP_LEN; p < pend;) { + *p &= (~((mln_u8_t)1 << i)); + ++as->nfree; + if (--n <= 0) break; + if (--i < 0) { + i = 7; + ++p; + } + } + } + if (as->large || as->nfree == as->base) { + mln_alloc_shm_chain_del(&as->pool->shm_head, &as->pool->shm_tail, as); + } +}) + +static inline mln_u8_t mln_alloc_shm_count_bits(mln_u8_t n) { + n = n - ((n >> 1) & 0x55); + n = (n & 0x33) + ((n >> 2) & 0x33); + n = (n + (n >> 4)) & 0x0F; + return n; +} + +mln_size_t mln_alloc_available_capacity(mln_alloc_t *pool) +{ + if (pool->mem == NULL) { + return pool->capacity? (pool->capacity - pool->in_used): M_ALLOC_INFINITE_SIZE; + } + + mln_alloc_shm_t *as = pool->shm_head; + mln_u8ptr_t p, pend; + mln_size_t sum = 0; + + for (; as != NULL; as = as->next) { + p = as->bitmap; + for (pend = p + M_ALLOC_SHM_BITMAP_LEN; p < pend; ++p) { + sum += (mln_size_t)mln_alloc_shm_count_bits(*p); + } + } + sum = (((mln_size_t)M_ALLOC_SHM_BITMAP_LEN) << 3) - sum; + return sum * M_ALLOC_SHM_BIT_SIZE; +} + +/* + * chain + */ +MLN_CHAIN_FUNC_DEFINE(static inline, \ + mln_blk, \ + mln_alloc_blk_t, \ + prev, \ + next); +MLN_CHAIN_FUNC_DEFINE(static inline, \ + mln_chunk, \ + mln_alloc_chunk_t, \ + prev, \ + next); +MLN_CHAIN_FUNC_DEFINE(static inline, \ + mln_alloc_shm, \ + mln_alloc_shm_t, \ + prev, \ + next); + diff --git a/src/mln_conf.c b/src/mln_conf.c index 19a77fb3..7aa38c74 100644 --- a/src/mln_conf.c +++ b/src/mln_conf.c @@ -334,7 +334,7 @@ static inline mln_conf_t *mln_conf_init(void) mln_lex_hooks_t hooks; struct mln_lex_attr lattr; - if ((pool = mln_alloc_init(NULL)) == NULL) { + if ((pool = mln_alloc_init(NULL, 0)) == NULL) { fprintf(stderr, "%s:%d: No memory.\n", __FUNCTION__, __LINE__); mln_rbtree_free(cf->domain); free(cf); diff --git a/src/mln_connection.c b/src/mln_connection.c index 14644630..589a4b12 100644 --- a/src/mln_connection.c +++ b/src/mln_connection.c @@ -64,7 +64,7 @@ static inline int mln_fd_is_nonblock(int fd) */ MLN_FUNC(, int, mln_tcp_conn_init, (mln_tcp_conn_t *tc, int sockfd), (tc, sockfd), { - tc->pool = mln_alloc_init(NULL); + tc->pool = mln_alloc_init(NULL, 0); if (tc->pool == NULL) return -1; tc->rcv_head = tc->rcv_tail = NULL; tc->snd_head = tc->snd_tail = NULL; diff --git a/src/mln_expr.c b/src/mln_expr.c index 6698aff1..dec73682 100644 --- a/src/mln_expr.c +++ b/src/mln_expr.c @@ -739,7 +739,7 @@ MLN_FUNC(, mln_expr_val_t *, mln_expr_run, (mln_string_t *exp, mln_expr_cb_t cb, hooks.dblq_handler = (lex_hook)mln_expr_dblq_handler; hooks.sglq_handler = (lex_hook)mln_expr_sglq_handler; - if ((pool = lattr.pool = mln_alloc_init(NULL)) == NULL) { + if ((pool = lattr.pool = mln_alloc_init(NULL, 0)) == NULL) { return NULL; } lattr.keywords = keywords; @@ -798,7 +798,7 @@ MLN_FUNC(, mln_expr_val_t *, mln_expr_run_file, (mln_string_t *path, mln_expr_cb hooks.dblq_handler = (lex_hook)mln_expr_dblq_handler; hooks.sglq_handler = (lex_hook)mln_expr_sglq_handler; - if ((pool = lattr.pool = mln_alloc_init(NULL)) == NULL) { + if ((pool = lattr.pool = mln_alloc_init(NULL, 0)) == NULL) { return NULL; } lattr.keywords = keywords; diff --git a/src/mln_file.c b/src/mln_file.c index 7db5e07b..924e5e30 100644 --- a/src/mln_file.c +++ b/src/mln_file.c @@ -33,7 +33,7 @@ MLN_FUNC(, mln_fileset_t *, mln_fileset_init, (mln_size_t max_file), (max_file), return NULL; } - fs->pool = mln_alloc_init(NULL); + fs->pool = mln_alloc_init(NULL, 0); if (fs->pool == NULL) { free(fs); return NULL; diff --git a/src/mln_lang.c b/src/mln_lang.c index 31800f7a..b4d20d79 100644 --- a/src/mln_lang.c +++ b/src/mln_lang.c @@ -749,7 +749,7 @@ mln_lang_t *mln_lang_new(mln_event_t *ev, mln_lang_run_ctl_t signal, mln_lang_ru struct mln_rbtree_attr rbattr; mln_alloc_t *pool; - if ((pool = mln_alloc_init(NULL)) == NULL) + if ((pool = mln_alloc_init(NULL, 0)) == NULL) return NULL; if ((lang = (mln_lang_t *)mln_alloc_m(pool, sizeof(mln_lang_t))) == NULL) { @@ -1026,7 +1026,7 @@ mln_lang_ctx_new(mln_lang_t *lang, void *data, mln_string_t *filename, mln_u32_t return NULL; } ctx->lang = lang; - if ((ctx->pool = mln_alloc_init(NULL)) == NULL) { + if ((ctx->pool = mln_alloc_init(NULL, 0)) == NULL) { mln_alloc_free(ctx); return NULL; } diff --git a/src/mln_lang_array.c b/src/mln_lang_array.c index 2c985968..857100a3 100644 --- a/src/mln_lang_array.c +++ b/src/mln_lang_array.c @@ -6,13 +6,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static int mln_lang_array_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); static int diff --git a/src/mln_lang_ast.c b/src/mln_lang_ast.c index 12f22041..d8e9d15b 100644 --- a/src/mln_lang_ast.c +++ b/src/mln_lang_ast.c @@ -3769,7 +3769,7 @@ MLN_FUNC(, void *, mln_lang_ast_generate, \ mln_alloc_t *internal_pool; mln_u8ptr_t ret; - if ((internal_pool = mln_alloc_init(NULL)) == NULL) { + if ((internal_pool = mln_alloc_init(NULL, 0)) == NULL) { return NULL; } lattr.pool = internal_pool; diff --git a/src/mln_lang_bool.c b/src/mln_lang_bool.c index 7277f9fa..7e38e4f2 100644 --- a/src/mln_lang_bool.c +++ b/src/mln_lang_bool.c @@ -6,13 +6,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static int mln_lang_bool_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); static int diff --git a/src/mln_lang_func.c b/src/mln_lang_func.c index 66bd96b3..42a82127 100644 --- a/src/mln_lang_func.c +++ b/src/mln_lang_func.c @@ -6,13 +6,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static int mln_lang_func_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); static int diff --git a/src/mln_lang_int.c b/src/mln_lang_int.c index e5f4b3bf..bf38fc9c 100644 --- a/src/mln_lang_int.c +++ b/src/mln_lang_int.c @@ -6,13 +6,6 @@ #include #include -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static inline mln_s64_t mln_lang_int_var_toint(mln_lang_var_t *var); static inline double mln_lang_int_var_toreal(mln_lang_var_t *var); static int diff --git a/src/mln_lang_nil.c b/src/mln_lang_nil.c index 54103a16..d7bbab51 100644 --- a/src/mln_lang_nil.c +++ b/src/mln_lang_nil.c @@ -5,13 +5,6 @@ #include "mln_lang_nil.h" #include -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static int mln_lang_nil_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); static int diff --git a/src/mln_lang_obj.c b/src/mln_lang_obj.c index fd81f742..f6e75462 100644 --- a/src/mln_lang_obj.c +++ b/src/mln_lang_obj.c @@ -6,13 +6,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static int mln_lang_obj_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); static int diff --git a/src/mln_lang_real.c b/src/mln_lang_real.c index e02e4cdc..e8f76444 100644 --- a/src/mln_lang_real.c +++ b/src/mln_lang_real.c @@ -7,13 +7,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static inline double mln_lang_real_var_toreal(mln_lang_var_t *var); static int mln_lang_real_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); diff --git a/src/mln_lang_str.c b/src/mln_lang_str.c index d85d2e69..d1888563 100644 --- a/src/mln_lang_str.c +++ b/src/mln_lang_str.c @@ -7,13 +7,6 @@ #include #include "mln_func.h" -#ifdef __DEBUG__ -#include -#define ASSERT(x) assert(x) -#else -#define ASSERT(x); -#endif - static inline mln_string_t *__mln_lang_str_var_tostring(mln_alloc_t *pool, mln_lang_var_t *var); static int mln_lang_str_assign(mln_lang_ctx_t *ctx, mln_lang_var_t **ret, mln_lang_var_t *op1, mln_lang_var_t *op2); diff --git a/t/alloc.c b/t/alloc.c index 19ae94b1..82150428 100644 --- a/t/alloc.c +++ b/t/alloc.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]) char *p; mln_alloc_t *pool; - pool = mln_alloc_init(NULL); + pool = mln_alloc_init(NULL, 0); if (pool == NULL) { fprintf(stderr, "pool init failed\n"); return -1; diff --git a/t/chain.c b/t/chain.c index 188829f5..1c3702f3 100644 --- a/t/chain.c +++ b/t/chain.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) mln_chain_t *c; mln_buf_t *b; - pool = mln_alloc_init(NULL); + pool = mln_alloc_init(NULL, 0); if (pool == NULL) { fprintf(stderr, "pool init failed.\n"); return -1; diff --git a/t/lex.c b/t/lex.c index aaa702bf..4012032d 100644 --- a/t/lex.c +++ b/t/lex.c @@ -88,7 +88,7 @@ int main(void) memset(&hooks, 0, sizeof(hooks)); hooks.dblq_handler = (lex_hook)mln_test_dblq_handler; - if ((lattr.pool = mln_alloc_init(NULL)) != NULL); + if ((lattr.pool = mln_alloc_init(NULL, 0)) != NULL); lattr.keywords = keywords; lattr.hooks = &hooks; lattr.preprocess = 1; diff --git a/t/parser_generator.c b/t/parser_generator.c index 631264ca..dcf7a261 100644 --- a/t/parser_generator.c +++ b/t/parser_generator.c @@ -30,7 +30,7 @@ int main(void) mln_lex_hooks_t hooks; mln_string_t code = mln_string("a + 1;\nb + a;\nc - b;\n"); - assert((pool = mln_alloc_init(NULL)) != NULL); + assert((pool = mln_alloc_init(NULL, 0)) != NULL); lattr.pool = pool; lattr.keywords = NULL;