|
|
| version 1.1, 2012/02/27 20:56:38 | version 1.1.2.1, 2012/02/27 20:56:38 |
|---|---|
| Line 0 | Line 1 |
| #include "global.h" | |
| /* | |
| * mpool_init() - Init memory pool | |
| * | |
| * return: =NULL error or !=NULL new allocated pool | |
| */ | |
| mpool_t * | |
| mpool_init(void) | |
| { | |
| mpool_t *mp; | |
| mp = malloc(sizeof(mpool_t)); | |
| if (!mp) { | |
| LOGERR; | |
| return NULL; | |
| } else | |
| memset(mp, 0, sizeof(mpool_t)); | |
| pthread_mutex_init(&mp->pool_mtx, NULL); | |
| return mp; | |
| } | |
| /* | |
| * mpool_destroy() - Destroy memory pool | |
| * | |
| * @mp = Memory pool | |
| * return: none | |
| */ | |
| void | |
| mpool_destroy(mpool_t ** __restrict mp) | |
| { | |
| struct tagAlloc *m; | |
| register int i; | |
| if (!mp && !*mp) | |
| return; | |
| mpool_lock(*mp); | |
| for (i = 0; i < MEM_BUCKETS; i++) { | |
| while ((m = TAILQ_FIRST(&(*mp)->pool_active[i]))) { | |
| TAILQ_REMOVE(&(*mp)->pool_active[i], m, alloc_node); | |
| if (m->alloc_mem) | |
| free(m->alloc_mem); | |
| free(m); | |
| } | |
| while ((m = TAILQ_FIRST(&(*mp)->pool_inactive[i]))) { | |
| TAILQ_REMOVE(&(*mp)->pool_inactive[i], m, alloc_node); | |
| if (m->alloc_mem) | |
| free(m->alloc_mem); | |
| free(m); | |
| } | |
| } | |
| mpool_unlock(*mp); | |
| pthread_mutex_destroy(&(*mp)->pool_mtx); | |
| free(*mp); | |
| *mp = NULL; | |
| } | |
| /* ----------------------------------------------------------- */ | |
| static inline long | |
| BucketIndex(u_int size) | |
| { | |
| register long b; | |
| if (!size--) | |
| return 0; /* min bucket position in array */ | |
| for (b = MEM_MIN_BUCKET; b < MEM_MAX_BUCKET; b++) | |
| if (!(size >> b)) | |
| break; | |
| return b - MEM_MIN_BUCKET; /* convert to bucket array index */ | |
| } | |
| static inline struct tagAlloc * | |
| pullInactive(mpool_t * __restrict mp, int idx) | |
| { | |
| struct tagAlloc *m = NULL; | |
| /* must be locked pool before use this function */ | |
| if ((m = TAILQ_FIRST(&mp->pool_inactive[idx]))) { | |
| TAILQ_REMOVE(&mp->pool_inactive[idx], m, alloc_node); | |
| /* clear name */ | |
| *m->alloc_name = 0; | |
| /* clear flags */ | |
| m->alloc_flags ^= m->alloc_flags; | |
| } | |
| return m; | |
| } | |
| /* | |
| * mpool_malloc() - Memory allocation | |
| * | |
| * @mp = Memory pool | |
| * @size = Size | |
| * @memname = Optional memory block name | |
| * return: NULL error or !=NULL ok allocated memory | |
| */ | |
| void * | |
| mpool_malloc(mpool_t * __restrict mp, u_int size, const char *memname) | |
| { | |
| struct tagAlloc *m; | |
| int idx, align; | |
| if (!mp) { | |
| sess_SetErr(EINVAL, "Pool not specified"); | |
| return NULL; | |
| } | |
| if (size > MEM_ALLOC_MAX) { | |
| sess_SetErr(ENOMEM, "Memory size is too large"); | |
| return NULL; | |
| } else | |
| size = (size + 3) & ~3; /* must align to 4 because needed room for sentinels */ | |
| idx = BucketIndex(size); | |
| mpool_lock(mp); | |
| /* get memory from cache if exists */ | |
| if (!(m = pullInactive(mp, idx))) { | |
| /* quota */ | |
| if (mp->pool_quota.max && | |
| (mp->pool_quota.curr + size) > mp->pool_quota.max) { | |
| sess_SetErr(ENOMEM, "Max.allocate memory quota has been reached"); | |
| mpool_unlock(mp); | |
| return NULL; | |
| } | |
| m = malloc(sizeof(struct tagAlloc)); | |
| if (!m) { | |
| LOGERR; | |
| mpool_unlock(mp); | |
| return NULL; | |
| } else | |
| memset(m, 0, sizeof(struct tagAlloc)); | |
| } | |
| if (memname) | |
| strlcpy(m->alloc_name, memname, sizeof m->alloc_name); | |
| if (!m->alloc_mem) { | |
| align = 1 << (idx + MEM_MIN_BUCKET); | |
| m->alloc_mem = malloc(align + 12); /* +12 sentinel bytes */ | |
| if (!m->alloc_mem) { | |
| LOGERR; | |
| free(m); | |
| mpool_unlock(mp); | |
| return NULL; | |
| } else /* quota */ | |
| mp->pool_quota.curr += size; | |
| } | |
| m->alloc_mem[0] = size / sizeof(u_int); | |
| m->alloc_mem[1] = MEM_MAGIC_START; | |
| m->alloc_mem[2 + size / sizeof(u_int)] = MEM_MAGIC_STOP; | |
| TAILQ_INSERT_HEAD(&mp->pool_active[idx], m, alloc_node); | |
| /* statistics */ | |
| mp->pool_calls.alloc++; | |
| mp->pool_bytes.alloc += size; | |
| mpool_unlock(mp); | |
| return mem_data(m, void*); | |
| } | |
| /* | |
| * mpool_free() Free allocated memory with mpool_alloc() | |
| * | |
| * @mp = Memory pool | |
| * @data = Allocated memory data | |
| * @purge = if !=0 force release memory block | |
| * return: <0 error or 0 ok released memory block | |
| */ | |
| int | |
| mpool_free(mpool_t * __restrict mp, void * __restrict data, int purge) | |
| { | |
| int idx; | |
| struct tagAlloc *m; | |
| if (!mp) { | |
| sess_SetErr(EINVAL, "Pool not specified"); | |
| return -1; | |
| } | |
| /* check address range & sentinel */ | |
| if (MEM_BADADDR(data) || MEM_CORRUPT(data)) { | |
| sess_SetErr(EFAULT, "Corrupted memory address"); | |
| return -2; | |
| } else | |
| idx = BucketIndex(((u_int*)data)[-2]); | |
| mpool_lock(mp); | |
| TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) | |
| if (mem_data(m, void*) == data) { | |
| TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); | |
| if (!purge) { | |
| TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node); | |
| /* statistics */ | |
| mp->pool_calls.cache++; | |
| mp->pool_bytes.cache += mem_size(m); | |
| } else { | |
| if (m->alloc_mem) | |
| free(m->alloc_mem); | |
| free(m); | |
| /* statistics */ | |
| mp->pool_calls.free++; | |
| mp->pool_bytes.free += mem_size(m); | |
| } | |
| break; | |
| } | |
| mpool_unlock(mp); | |
| return 0; | |
| } | |
| /* | |
| * mpool_free2() Free allocated memory with mpool_alloc() by size and memory name | |
| * | |
| * @mp = Memory pool | |
| * @size = Allocated memory data size | |
| * @memname = Memory name | |
| * @purge = if !=0 force release memory block | |
| * return: <0 error or 0 ok released memory block | |
| */ | |
| int | |
| mpool_free2(mpool_t * __restrict mp, u_int size, const char *memname, int purge) | |
| { | |
| int idx; | |
| struct tagAlloc *m; | |
| if (!mp || !memname) { | |
| sess_SetErr(EINVAL, "Pool or memory name is not specified"); | |
| return -1; | |
| } else | |
| idx = BucketIndex(size); | |
| mpool_lock(mp); | |
| TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) | |
| if (!strcmp(m->alloc_name, memname)) { | |
| TAILQ_REMOVE(&mp->pool_active[idx], m, alloc_node); | |
| if (!purge) { | |
| TAILQ_INSERT_HEAD(&mp->pool_inactive[idx], m, alloc_node); | |
| /* statistics */ | |
| mp->pool_calls.cache++; | |
| mp->pool_bytes.cache += mem_size(m); | |
| } else { | |
| if (m->alloc_mem) | |
| free(m->alloc_mem); | |
| free(m); | |
| /* statistics */ | |
| mp->pool_calls.free++; | |
| mp->pool_bytes.free += mem_size(m); | |
| } | |
| break; | |
| } | |
| mpool_unlock(mp); | |
| return 0; | |
| } | |
| /* | |
| * mpool_getmembynam() Find allocated memory block by size and memory name | |
| * | |
| * @mp = Memory pool | |
| * @size = Memory size | |
| * @memname = Memory name | |
| * return: NULL error or not found and !=NULL allocated memory | |
| */ | |
| inline struct tagAlloc * | |
| mpool_getmembynam(mpool_t * __restrict mp, u_int size, const char *memname) | |
| { | |
| int idx; | |
| struct tagAlloc *m = NULL; | |
| if (!mp || !memname) | |
| return NULL; | |
| idx = BucketIndex(size); | |
| TAILQ_FOREACH(m, &mp->pool_active[idx], alloc_node) | |
| if (!strcmp(m->alloc_name, memname)) | |
| break; | |
| return mem_data(m, void*); | |
| } |