|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <ngx_config.h> | 
|  | #include <ngx_core.h> | 
|  |  | 
|  |  | 
|  | static void *ngx_palloc_block(ngx_pool_t *pool, size_t size); | 
|  | static void *ngx_palloc_large(ngx_pool_t *pool, size_t size); | 
|  |  | 
|  |  | 
|  | ngx_pool_t * | 
|  | ngx_create_pool(size_t size, ngx_log_t *log) | 
|  | { | 
|  | ngx_pool_t  *p; | 
|  |  | 
|  | p = ngx_alloc(size, log); | 
|  | if (p == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | p->d.last = (u_char *) p + sizeof(ngx_pool_t); | 
|  | p->d.end = (u_char *) p + size; | 
|  | p->d.next = NULL; | 
|  |  | 
|  | size = size - sizeof(ngx_pool_t); | 
|  | p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; | 
|  |  | 
|  | p->current = p; | 
|  | p->chain = NULL; | 
|  | p->large = NULL; | 
|  | p->cleanup = NULL; | 
|  | p->log = log; | 
|  |  | 
|  | return p; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_destroy_pool(ngx_pool_t *pool) | 
|  | { | 
|  | ngx_pool_t          *p, *n; | 
|  | ngx_pool_large_t    *l; | 
|  | ngx_pool_cleanup_t  *c; | 
|  |  | 
|  | for (c = pool->cleanup; c; c = c->next) { | 
|  | if (c->handler) { | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, | 
|  | "run cleanup: %p", c); | 
|  | c->handler(c->data); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (l = pool->large; l; l = l->next) { | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); | 
|  |  | 
|  | if (l->alloc) { | 
|  | ngx_free(l->alloc); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if (NGX_DEBUG) | 
|  |  | 
|  | /* | 
|  | * we could allocate the pool->log from this pool | 
|  | * so we can not use this log while the free()ing the pool | 
|  | */ | 
|  |  | 
|  | for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { | 
|  | ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0, | 
|  | "free: %p, unused: %uz", p, p->d.end - p->d.last); | 
|  |  | 
|  | if (n == NULL) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif | 
|  |  | 
|  | for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { | 
|  | ngx_free(p); | 
|  |  | 
|  | if (n == NULL) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_reset_pool(ngx_pool_t *pool) | 
|  | { | 
|  | ngx_pool_t        *p; | 
|  | ngx_pool_large_t  *l; | 
|  |  | 
|  | for (l = pool->large; l; l = l->next) { | 
|  | if (l->alloc) { | 
|  | ngx_free(l->alloc); | 
|  | } | 
|  | } | 
|  |  | 
|  | pool->large = NULL; | 
|  |  | 
|  | for (p = pool; p; p = p->d.next) { | 
|  | p->d.last = (u_char *) p + sizeof(ngx_pool_t); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void * | 
|  | ngx_palloc(ngx_pool_t *pool, size_t size) | 
|  | { | 
|  | u_char      *m; | 
|  | ngx_pool_t  *p; | 
|  |  | 
|  | if (size <= pool->max) { | 
|  |  | 
|  | p = pool->current; | 
|  |  | 
|  | do { | 
|  | m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); | 
|  |  | 
|  | if ((size_t) (p->d.end - m) >= size) { | 
|  | p->d.last = m + size; | 
|  |  | 
|  | return m; | 
|  | } | 
|  |  | 
|  | p = p->d.next; | 
|  |  | 
|  | } while (p); | 
|  |  | 
|  | return ngx_palloc_block(pool, size); | 
|  | } | 
|  |  | 
|  | return ngx_palloc_large(pool, size); | 
|  | } | 
|  |  | 
|  |  | 
|  | void * | 
|  | ngx_pnalloc(ngx_pool_t *pool, size_t size) | 
|  | { | 
|  | u_char      *m; | 
|  | ngx_pool_t  *p; | 
|  |  | 
|  | if (size <= pool->max) { | 
|  |  | 
|  | p = pool->current; | 
|  |  | 
|  | do { | 
|  | m = p->d.last; | 
|  |  | 
|  | if ((size_t) (p->d.end - m) >= size) { | 
|  | p->d.last = m + size; | 
|  |  | 
|  | return m; | 
|  | } | 
|  |  | 
|  | p = p->d.next; | 
|  |  | 
|  | } while (p); | 
|  |  | 
|  | return ngx_palloc_block(pool, size); | 
|  | } | 
|  |  | 
|  | return ngx_palloc_large(pool, size); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void * | 
|  | ngx_palloc_block(ngx_pool_t *pool, size_t size) | 
|  | { | 
|  | u_char      *m; | 
|  | size_t       psize; | 
|  | ngx_pool_t  *p, *new, *current; | 
|  |  | 
|  | psize = (size_t) (pool->d.end - (u_char *) pool); | 
|  |  | 
|  | m = ngx_alloc(psize, pool->log); | 
|  | if (m == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | new = (ngx_pool_t *) m; | 
|  |  | 
|  | new->d.end = m + psize; | 
|  | new->d.next = NULL; | 
|  |  | 
|  | m += sizeof(ngx_pool_data_t); | 
|  | m = ngx_align_ptr(m, NGX_ALIGNMENT); | 
|  | new->d.last = m + size; | 
|  |  | 
|  | current = pool->current; | 
|  |  | 
|  | for (p = current; p->d.next; p = p->d.next) { | 
|  | if ((size_t) (p->d.end - p->d.last) < NGX_ALIGNMENT) { | 
|  | current = p->d.next; | 
|  | } | 
|  | } | 
|  |  | 
|  | p->d.next = new; | 
|  |  | 
|  | pool->current = current ? current : new; | 
|  |  | 
|  | return m; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void * | 
|  | ngx_palloc_large(ngx_pool_t *pool, size_t size) | 
|  | { | 
|  | void              *p; | 
|  | ngx_pool_large_t  *large; | 
|  |  | 
|  | p = ngx_alloc(size, pool->log); | 
|  | if (p == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); | 
|  | if (large == NULL) { | 
|  | ngx_free(p); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | large->alloc = p; | 
|  | large->next = pool->large; | 
|  | pool->large = large; | 
|  |  | 
|  | return p; | 
|  | } | 
|  |  | 
|  |  | 
|  | void * | 
|  | ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment) | 
|  | { | 
|  | void              *p; | 
|  | ngx_pool_large_t  *large; | 
|  |  | 
|  | p = ngx_memalign(alignment, size, pool->log); | 
|  | if (p == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); | 
|  | if (large == NULL) { | 
|  | ngx_free(p); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | large->alloc = p; | 
|  | large->next = pool->large; | 
|  | pool->large = large; | 
|  |  | 
|  | return p; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_int_t | 
|  | ngx_pfree(ngx_pool_t *pool, void *p) | 
|  | { | 
|  | ngx_pool_large_t  *l; | 
|  |  | 
|  | for (l = pool->large; l; l = l->next) { | 
|  | if (p == l->alloc) { | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, | 
|  | "free: %p", l->alloc); | 
|  | ngx_free(l->alloc); | 
|  | l->alloc = NULL; | 
|  |  | 
|  | return NGX_OK; | 
|  | } | 
|  | } | 
|  |  | 
|  | return NGX_DECLINED; | 
|  | } | 
|  |  | 
|  |  | 
|  | void * | 
|  | ngx_pcalloc(ngx_pool_t *pool, size_t size) | 
|  | { | 
|  | void *p; | 
|  |  | 
|  | p = ngx_palloc(pool, size); | 
|  | if (p) { | 
|  | ngx_memzero(p, size); | 
|  | } | 
|  |  | 
|  | return p; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_pool_cleanup_t * | 
|  | ngx_pool_cleanup_add(ngx_pool_t *p, size_t size) | 
|  | { | 
|  | ngx_pool_cleanup_t  *c; | 
|  |  | 
|  | c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t)); | 
|  | if (c == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (size) { | 
|  | c->data = ngx_palloc(p, size); | 
|  | if (c->data == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | } else { | 
|  | c->data = NULL; | 
|  | } | 
|  |  | 
|  | c->handler = NULL; | 
|  | c->next = p->cleanup; | 
|  |  | 
|  | p->cleanup = c; | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c); | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_pool_cleanup_file(void *data) | 
|  | { | 
|  | ngx_pool_cleanup_file_t  *c = data; | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d", | 
|  | c->fd); | 
|  |  | 
|  | if (ngx_close_file(c->fd) == NGX_FILE_ERROR) { | 
|  | ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
|  | ngx_close_file_n " \"%s\" failed", c->name); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_pool_delete_file(void *data) | 
|  | { | 
|  | ngx_pool_cleanup_file_t  *c = data; | 
|  |  | 
|  | ngx_err_t  err; | 
|  |  | 
|  | ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s", | 
|  | c->fd, c->name); | 
|  |  | 
|  | if (ngx_delete_file(c->name) == NGX_FILE_ERROR) { | 
|  | err = ngx_errno; | 
|  |  | 
|  | if (err != NGX_ENOENT) { | 
|  | ngx_log_error(NGX_LOG_CRIT, c->log, err, | 
|  | ngx_delete_file_n " \"%s\" failed", c->name); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ngx_close_file(c->fd) == NGX_FILE_ERROR) { | 
|  | ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | 
|  | ngx_close_file_n " \"%s\" failed", c->name); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #if 0 | 
|  |  | 
|  | static void * | 
|  | ngx_get_cached_block(size_t size) | 
|  | { | 
|  | void                     *p; | 
|  | ngx_cached_block_slot_t  *slot; | 
|  |  | 
|  | if (ngx_cycle->cache == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize]; | 
|  |  | 
|  | slot->tries++; | 
|  |  | 
|  | if (slot->number) { | 
|  | p = slot->block; | 
|  | slot->block = slot->block->next; | 
|  | slot->number--; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #endif |