diff options
Diffstat (limited to 'src/nxt_mem_pool.c')
-rw-r--r-- | src/nxt_mem_pool.c | 644 |
1 files changed, 0 insertions, 644 deletions
diff --git a/src/nxt_mem_pool.c b/src/nxt_mem_pool.c deleted file mode 100644 index 7817bac7..00000000 --- a/src/nxt_mem_pool.c +++ /dev/null @@ -1,644 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -/* - * The pool allocator provides cheap allocation of small objects. - * The objects are allocated from larger preallocated chunks. - * - * aligned and non-aligned allocations, - * cache of reusable objects, lvlhsh-specific cache - * eliminating align padding - * data locality - * freeing on pool destruction - * freeing large allocations - */ - - -static void *nxt_mem_pool_align(nxt_mem_pool_t *mp, size_t alignment, - size_t size); -static void *nxt_mem_pool_ext(nxt_mem_pool_t *mp, size_t size); -static nxt_mem_pool_chunk_t *nxt_mem_pool_next_chunk(nxt_mem_pool_t *mp, - nxt_mem_pool_chunk_t *chunk); -static nxt_mem_pool_chunk_t *nxt_mem_pool_chunk(nxt_mem_pool_t *mp); -static void *nxt_mem_lvlhsh_alloc_chunk(nxt_mem_pool_cache_t *cache, - size_t size, nxt_uint_t nalloc); - - -#if (NXT_DEBUG) - -static nxt_bool_t -nxt_mem_pool_thread_is_invalid(nxt_mem_pool_t *mp) -{ - nxt_tid_t tid; - nxt_thread_t *thr; - - thr = nxt_thread(); - tid = nxt_thread_tid(thr); - - if (nxt_slow_path(mp->tid != tid)) { - - if (mp->pid == nxt_pid) { - nxt_log_alert(thr->log, "mem_pool locked by thread %PT", mp->tid); - nxt_abort(); - return 1; - } - - mp->pid = nxt_pid; - mp->tid = tid; - } - - return 0; -} - - -/* SunC does not support C99 variadic macro with empty __VA_ARGS__. */ - -#define \ -nxt_mem_pool_thread_assert(mp) \ - if (nxt_mem_pool_thread_is_invalid(mp)) \ - return - - -#define \ -nxt_mem_pool_thread_assert_return(mp, ret) \ - if (nxt_mem_pool_thread_is_invalid(mp)) \ - return ret - - -#else /* !(NXT_DEBUG) */ - -#define \ -nxt_mem_pool_thread_assert(mp) - -#define \ -nxt_mem_pool_thread_assert_return(mp, ret) - -#endif - - -nxt_mem_pool_t * -nxt_mem_pool_create(size_t size) -{ - u_char *p; - size_t min_ext_size; - nxt_mem_pool_t *mp; - - mp = nxt_malloc(size); - - if (nxt_fast_path(mp != NULL)) { - - mp->chunk_size = (uint32_t) size; - - min_ext_size = size - sizeof(nxt_mem_pool_t) + 1; - mp->min_ext_size = (uint32_t) nxt_min(min_ext_size, - NXT_MEM_POOL_MIN_EXT_SIZE); - - nxt_malloc_usable_size(mp, size); - - p = (u_char *) mp; - - mp->chunk.free = p + sizeof(nxt_mem_pool_t); - mp->chunk.end = p + size; - mp->chunk.next = NULL; - mp->chunk.fails = 0; - - mp->current = &mp->chunk; - mp->ext = NULL; - mp->cleanup = NULL; - mp->cache = NULL; - - nxt_thread_log_debug("mem pool chunk size:%uz avail:%uz", - size, mp->chunk.end - mp->chunk.free); - - nxt_mem_pool_debug_lock(mp, nxt_thread_tid(NULL)); - } - - return mp; -} - - -void -nxt_mem_pool_destroy(nxt_mem_pool_t *mp) -{ - nxt_task_t *task; - nxt_mem_pool_ext_t *ext; - nxt_mem_pool_chunk_t *chunk, *next; - nxt_mem_pool_cleanup_t *mpcl; - - task = NULL; - - nxt_mem_pool_thread_assert(mp); - - for (mpcl = mp->cleanup; mpcl != NULL; mpcl = mpcl->next) { - if (mpcl->handler != NULL) { - nxt_thread_log_debug("mem pool cleanup: %p", mpcl); - mpcl->handler(task, mpcl->data); - } - } - - for (ext = mp->ext; ext != NULL; ext = ext->next) { - if (ext->data != NULL) { - nxt_free(ext->data); - } - } - - chunk = &mp->chunk; - - do { - nxt_thread_log_debug("mem pool chunk fails:%uD unused:%uz", - chunk->fails, chunk->end - chunk->free); - next = chunk->next; - nxt_free(chunk); - chunk = next; - - } while (chunk != NULL); -} - - -void * -nxt_mem_align(nxt_mem_pool_t *mp, size_t alignment, size_t size) -{ - nxt_mem_pool_thread_assert_return(mp, NULL); - - if (nxt_fast_path(size < mp->min_ext_size)) { - return nxt_mem_pool_align(mp, alignment, size); - } - - return nxt_mem_pool_ext(mp, size); -} - - -void * -nxt_mem_zalign(nxt_mem_pool_t *mp, size_t alignment, size_t size) -{ - void *p; - - p = nxt_mem_align(mp, alignment, size); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, size); - } - - return p; -} - - -/* - * Zero-filled aligned allocation, suitable for struct - * allocation without long double and SIMD values. - */ - -void * -nxt_mem_zalloc(nxt_mem_pool_t *mp, size_t size) -{ - void *p; - - p = nxt_mem_alloc(mp, size); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, size); - } - - return p; -} - - -void * -nxt_mem_buf(nxt_mem_pool_t *mp, size_t *sizep, nxt_uint_t flags) -{ - u_char *p; - size_t size; - - nxt_mem_pool_thread_assert_return(mp, NULL); - - size = *sizep; - - if (nxt_fast_path(size >= mp->min_ext_size)) { - - nxt_malloc_cutback(flags & NXT_MEM_BUF_CUTBACK, size); - - /* Windows only: try to minimize number of allocated pages. */ - p = nxt_mem_pool_ext(mp, size); - if (p != NULL) { - - if (flags & NXT_MEM_BUF_USABLE) { - nxt_malloc_usable_size(p, size); - } - - *sizep = size; - } - - return p; - } - - return nxt_mem_pool_align(mp, NXT_ALIGNMENT, size); -} - - -/* Non-aligned allocation, suitable for string allocation. */ - -void * -nxt_mem_nalloc(nxt_mem_pool_t *mp, size_t size) -{ - u_char *p; - nxt_mem_pool_chunk_t *chunk; - - nxt_mem_pool_thread_assert_return(mp, NULL); - - if (nxt_slow_path(size >= mp->min_ext_size)) { - return nxt_mem_pool_ext(mp, size); - } - - chunk = mp->current; - - for ( ;; ) { - p = chunk->end - size; - - if (nxt_fast_path(p >= chunk->free)) { - chunk->end = p; - return p; - } - - chunk = nxt_mem_pool_next_chunk(mp, chunk); - - if (nxt_slow_path(chunk == NULL)) { - return NULL; - } - } -} - - -/* An attempt to deallocate a large allocation outside pool. */ - -nxt_int_t -nxt_mem_free(nxt_mem_pool_t *mp, void *p) -{ - nxt_mem_pool_ext_t *ext; - - nxt_mem_pool_thread_assert_return(mp, NXT_DECLINED); - - for (ext = mp->ext; ext != NULL; ext = ext->next) { - - if (p == ext->data) { - nxt_free(ext->data); - ext->data = NULL; - - return NXT_OK; - } - } - - return NXT_DECLINED; -} - - -static void * -nxt_mem_pool_ext(nxt_mem_pool_t *mp, size_t size) -{ - void *p; - nxt_mem_pool_ext_t *ext; - - ext = nxt_mem_pool_align(mp, sizeof(void *), sizeof(nxt_mem_pool_ext_t)); - - if (nxt_fast_path(ext != NULL)) { - p = nxt_malloc(size); - - if (nxt_fast_path(p != NULL)) { - ext->data = p; - ext->next = mp->ext; - mp->ext = ext; - - return p; - } - } - - return NULL; -} - - -static void * -nxt_mem_pool_align(nxt_mem_pool_t *mp, size_t alignment, size_t size) -{ - u_char *p, *f; - nxt_mem_pool_chunk_t *chunk; - - chunk = mp->current; - - for ( ;; ) { - - p = nxt_align_ptr(chunk->free, alignment); - f = p + size; - - if (nxt_fast_path(f <= chunk->end)) { - chunk->free = f; - return p; - } - - chunk = nxt_mem_pool_next_chunk(mp, chunk); - - if (nxt_slow_path(chunk == NULL)) { - return NULL; - } - } -} - - -static nxt_mem_pool_chunk_t * -nxt_mem_pool_next_chunk(nxt_mem_pool_t *mp, nxt_mem_pool_chunk_t *chunk) -{ - nxt_bool_t full; - - full = (chunk->free == chunk->end || chunk->fails++ > 10); - - chunk = chunk->next; - - if (chunk == NULL) { - chunk = nxt_mem_pool_chunk(mp); - - if (nxt_slow_path(chunk == NULL)) { - return NULL; - } - } - - if (full) { - mp->current = chunk; - } - - return chunk; -} - - -static nxt_mem_pool_chunk_t * -nxt_mem_pool_chunk(nxt_mem_pool_t *mp) -{ - u_char *p; - size_t size; - nxt_mem_pool_chunk_t *ch, *chunk; - - size = mp->chunk_size; - - chunk = nxt_malloc(size); - - if (nxt_fast_path(chunk != NULL)) { - - nxt_malloc_usable_size(chunk, size); - - p = (u_char *) chunk; - - chunk->free = p + sizeof(nxt_mem_pool_chunk_t); - chunk->end = p + size; - chunk->next = NULL; - chunk->fails = 0; - - for (ch = mp->current; ch->next; ch = ch->next) { /* void */ } - - ch->next = chunk; - } - - return chunk; -} - - -nxt_mem_pool_cleanup_t * -nxt_mem_pool_cleanup(nxt_mem_pool_t *mp, size_t size) -{ - nxt_mem_pool_cleanup_t *mpcl; - - nxt_mem_pool_thread_assert_return(mp, NULL); - - mpcl = nxt_mem_pool_align(mp, sizeof(void *), - sizeof(nxt_mem_pool_cleanup_t)); - if (nxt_fast_path(mpcl != NULL)) { - - mpcl->handler = NULL; - mpcl->data = NULL; - - if (size != 0) { - mpcl->data = nxt_mem_alloc(mp, size); - if (nxt_slow_path(mpcl->data == NULL)) { - return NULL; - } - } - - mpcl->next = mp->cleanup; - mp->cleanup = mpcl; - - nxt_thread_log_debug("mem pool cleanup add: %p", mpcl); - } - - return mpcl; -} - - -/* Allocation of reusable object with specified size. */ - -void * -nxt_mem_cache_alloc0(nxt_mem_pool_t *mp, size_t size) -{ - void **pp; - nxt_mem_pool_cache_t *cache; - - nxt_mem_pool_thread_assert_return(mp, NULL); - - for (cache = mp->cache; cache != NULL; cache = cache->next) { - - if (cache->size == size && cache->nalloc == 0) { - - if (cache->free != NULL) { - pp = cache->free; - cache->free = *pp; - return pp; - } - - break; - } - } - - return nxt_mem_alloc(mp, size); -} - - -void * -nxt_mem_cache_zalloc0(nxt_mem_pool_t *mp, size_t size) -{ - void *p; - - p = nxt_mem_cache_alloc0(mp, size); - - if (nxt_fast_path(p != NULL)) { - nxt_memzero(p, size); - } - - return p; -} - - -/* Deallocation of reusable object with specified size. */ - -void -nxt_mem_cache_free0(nxt_mem_pool_t *mp, void *p, size_t size) -{ - void **pp; - nxt_mem_pool_cache_t *cache, **pcache; - - nxt_mem_pool_thread_assert(mp); - - pp = p; - - pcache = &mp->cache; - for (cache = mp->cache; cache != NULL; cache = cache->next) { - - if (cache->size == size && cache->nalloc == 0) { - *pp = cache->free; - cache->free = p; - return; - } - - pcache = &cache->next; - } - - /* Non-lvlhash caches are created only on return. */ - - cache = nxt_mem_pool_align(mp, sizeof(void *), - sizeof(nxt_mem_pool_cache_t)); - if (nxt_fast_path(cache != NULL)) { - *pp = NULL; - cache->size = (uint32_t) size; - cache->nalloc = 0; - cache->free = p; - cache->next = NULL; - *pcache = cache; - } -} - - -/* - * lvlhsh requires allocations aligned to a size of the allocations. - * This is not issue for slab-like allocators, but glibc allocator may - * waste memory on such aligned allocations. So nxt_mem_lvlhsh_alloc() - * allocates memory in chunks specified by the "nalloc" parameter - * except the first allocation. The first lvlhsh allocation is a bucket - * allocation and it is enough for small hashes and for early stage - * of a hash. By default lvlhsh uses 128-bytes buckets and levels. - * This allows to search up to 10 entries in one memory access and - * up to 160 entries in two memory accesses on 64-bit platform. - * And on 32-bit platform up to 15 entries and up to 480 entries - * respectively. - * - * After the bucket will be filled up with 10 64-bit entries or 15 - * 32-bit entries, lvlhsh will expand it to a level and content - * of the first bucket will spread to the level's new buckets. - * Number of the new buckets may be up to 11 on 64-bit or 16 on 32-bit - * platforms. It's better to allocate them together to eliminate - * wasting memory and CPU time. - * - * The "nalloc" should be 16 if bucket size is 128 bytes. - */ - - -/* Allocation of lvlhsh level or bucket with specified size. */ - -void * -nxt_mem_lvlhsh_alloc(void *ctx, size_t size, nxt_uint_t nalloc) -{ - void *p, **pp; - nxt_mem_pool_t *mp; - nxt_mem_pool_cache_t *cache; - - mp = ctx; - - nxt_mem_pool_thread_assert_return(mp, NULL); - - for (cache = mp->cache; cache != NULL; cache = cache->next) { - - if (cache->size == size && cache->nalloc != 0) { - - if (cache->free != NULL) { - pp = cache->free; - cache->free = *pp; - return pp; - } - - return nxt_mem_lvlhsh_alloc_chunk(cache, size, nalloc); - } - } - - cache = nxt_mem_pool_align(mp, sizeof(void *), - sizeof(nxt_mem_pool_cache_t)); - if (nxt_fast_path(cache != NULL)) { - - p = nxt_memalign(size, size); - - if (nxt_fast_path(p != NULL)) { - cache->size = (uint32_t) size; - cache->nalloc = nalloc; - cache->free = NULL; - cache->next = mp->cache; - mp->cache = cache; - return p; - } - } - - return NULL; -} - - -static void * -nxt_mem_lvlhsh_alloc_chunk(nxt_mem_pool_cache_t *cache, size_t size, - nxt_uint_t nalloc) -{ - char *m, *p, *end; - void **pp; - size_t n; - - n = (nalloc == 0) ? 1 : nalloc; - n *= size; - - m = nxt_memalign(size, n); - - if (nxt_fast_path(m != NULL)) { - - pp = &cache->free; - end = m + n; - - for (p = m + size; p < end; p = p + size) { - *pp = p; - pp = (void **) p; - } - - *pp = NULL; - } - - return m; -} - - -/* Deallocation of lvlhsh level or bucket with specified size. */ - -void -nxt_mem_lvlhsh_free(void *ctx, void *p, size_t size) -{ - void **pp; - nxt_mem_pool_t *mp; - nxt_mem_pool_cache_t *cache; - - mp = ctx; - - nxt_mem_pool_thread_assert(mp); - - pp = p; - - for (cache = mp->cache; cache != NULL; cache = cache->next) { - - if (cache->size == size && cache->nalloc != 0) { - *pp = cache->free; - cache->free = p; - return; - } - } -} |