首页 > 代码库 > Nginx源码完全注释(7)ngx_palloc.h/ngx_palloc.c

Nginx源码完全注释(7)ngx_palloc.h/ngx_palloc.c

ngx_palloc.h

/* * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86. * On Windows NT it decreases a number of locked pages in a kernel. */#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)#define NGX_POOL_ALIGNMENT       16#define NGX_MIN_POOL_SIZE                                                         ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),                          NGX_POOL_ALIGNMENT)typedef void (*ngx_pool_cleanup_pt)(void *data);typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;struct ngx_pool_cleanup_s {    ngx_pool_cleanup_pt   handler;    void                 *data;    ngx_pool_cleanup_t   *next;};typedef struct ngx_pool_large_s  ngx_pool_large_t;struct ngx_pool_large_s {    ngx_pool_large_t     *next;    void                 *alloc;};typedef struct {    u_char               *last;     // 数据存储的已用区尾地址    u_char               *end;      // 数据存储区的尾地址    ngx_pool_t           *next;     // 下一个内存池地址    ngx_uint_t            failed;   // 失败次数} ngx_pool_data_t;struct ngx_pool_s {    ngx_pool_data_t       d;            // 数据区    size_t                max;          // 内存池的最大存储空间    ngx_pool_t           *current;      // 内存池    ngx_chain_t          *chain;    ngx_pool_large_t     *large;        // 用于存储大数据,链表结构    ngx_pool_cleanup_t   *cleanup;      // 用于清理,链表结构    ngx_log_t            *log;};typedef struct {    ngx_fd_t              fd;           // 文件描述符,用于 ngx_pool_cleanup_file    u_char               *name;         // 文件名,用于 ngx_pool_delete_file    ngx_log_t            *log;} ngx_pool_cleanup_file_t;void *ngx_alloc(size_t size, ngx_log_t *log);void *ngx_calloc(size_t size, ngx_log_t *log);ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);void ngx_destroy_pool(ngx_pool_t *pool);void ngx_reset_pool(ngx_pool_t *pool);void *ngx_palloc(ngx_pool_t *pool, size_t size);void *ngx_pnalloc(ngx_pool_t *pool, size_t size);void *ngx_pcalloc(ngx_pool_t *pool, size_t size);void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);void ngx_pool_cleanup_file(void *data);void ngx_pool_delete_file(void *data);

ngx_palloc.c

static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);// 创建 size 大小的内存池ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log){    ngx_pool_t  *p;    p = ngx_memalign(NGX_POOL_ALIGNMENT, 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;    p->d.failed = 0;    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;}// 销毁内存池 poolvoidngx_destroy_pool(ngx_pool_t *pool){    ngx_pool_t          *p, *n;    ngx_pool_large_t    *l;    ngx_pool_cleanup_t  *c;    // 处理 pool->cleanup 链表,处理函数由此前赋值到 pool->cleanup->handler 的函数指针确定    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);        }    }    // 释放 pool->large 链表    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 cannot use this log while 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    // 释放 pool->d 链表    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {        ngx_free(p);        if (n == NULL) {            break;        }    }}// 重置内存池voidngx_reset_pool(ngx_pool_t *pool){    ngx_pool_t        *p;    ngx_pool_large_t  *l;    // 释放 large 链的每个节点的内存    for (l = pool->large; l; l = l->next) {        if (l->alloc) {            ngx_free(l->alloc);        }    }    pool->large = NULL;    // 重置数据 d 链的每个节点,即重置每个节点的可用区首地址 d.last    for (p = pool; p; p = p->d.next) {        p->d.last = (u_char *) p + sizeof(ngx_pool_t);    }}// 从内存池 pool 分配大小为 size 的内存块,并返回其地址// 是被外部使用最多的内存池相关 API,并且考虑对齐问题void *ngx_palloc(ngx_pool_t *pool, size_t size){    u_char      *m;    ngx_pool_t  *p;    // 如果还未超出内存池的 max 值,超过了则用 large    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);        // 现有节点都不给力,重新分配一个 d 节点        return ngx_palloc_block(pool, size);    }    // size 超过 pool->max,从 large 取    return ngx_palloc_large(pool, size);}// 类似 ngx_palloc,不考虑对齐问题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;    // pool 结构定义区和 pool->d 数据区的总大小    psize = (size_t) (pool->d.end - (u_char *) pool);    // 分配 psize 大小的内存    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);    if (m == NULL) {        return NULL;    }    // 用 new 来表示上面分配的新内存块    new = (ngx_pool_t *) m;    // 初始化这个 new,设定 new 的 d.end、d.next、d.failed    new->d.end = m + psize;    new->d.next = NULL;    new->d.failed = 0;    // m 加上内存池数据定义结构体的大小    m += sizeof(ngx_pool_data_t);    // 内存对齐 m    m = ngx_align_ptr(m, NGX_ALIGNMENT);    // 设定 new 的 d.last    new->d.last = m + size;    current = pool->current;    // TODO    for (p = current; p->d.next; p = p->d.next) {        if (p->d.failed++ > 4) {            current = p->d.next;        }    }    // new 节点放入内存池数据链    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_uint_t         n;    ngx_pool_large_t  *large;    // 分配 size 大小的内存    p = ngx_alloc(size, pool->log);    if (p == NULL) {        return NULL;    }    n = 0;    // 在 pool 的 large 链中寻找存储区为空的节点,把新分配的内存区首地址赋给它    for (large = pool->large; large; large = large->next) {            // 找到 large 链末尾,在其后插入之,并返回给外部使用        if (large->alloc == NULL) {            large->alloc = p;            return p;        }        // 查看的 large 节点超过 3 个,不再尝试和寻找,由下面代码实现创建新 large 节点的逻辑        if (n++ > 3) {            break;        }    }    // 创建 large 链的一个新节点,如果失败则释放刚才创建的 size 大小的内存,并返回 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;    // 创建一块 size 大小的内存,内存以 alignment 字节对齐    p = ngx_memalign(alignment, size, pool->log);    if (p == NULL) {        return NULL;    }    // 创建一个 large 节点    large = ngx_palloc(pool, sizeof(ngx_pool_large_t));    if (large == NULL) {        ngx_free(p);        return NULL;    }    // 将这个新的 large 节点交付给 pool 的 large 字段    large->alloc = p;    large->next = pool->large;    pool->large = large;    return p;}ngx_int_tngx_pfree(ngx_pool_t *pool, void *p){    ngx_pool_large_t  *l;    // 逐一释放 large 链表的每一个节点    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;}// 封装 palloc 为 pcalloc,实现分配内存并初始化为 0void *ngx_pcalloc(ngx_pool_t *pool, size_t size){    void *p;    p = ngx_palloc(pool, size);    if (p) {        ngx_memzero(p, size);    }    return p;}// 向 cleanup 链添加 p->cleanup 这个节点ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size){    ngx_pool_cleanup_t  *c;    // 创建一个 cleanup 节点    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));    if (c == NULL) {        return NULL;    }    if (size) {        // cleanup 节点数据区        c->data = http://www.mamicode.com/ngx_palloc(p, size);"keyword" style="font-weight: bold;">if (c->data =http://www.mamicode.com/= NULL) {"keyword" style="font-weight: bold;">return NULL;        }    } else {        c->data = http://www.mamicode.com/NULL;"comment" style="color: #888888;">// 善后    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;}// 查找指定的 fd,且其 handler 为 ngx_pool_cleanup_file,执行相应动作// 这里面有一个遍历的操作voidngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd){    ngx_pool_cleanup_t       *c;    ngx_pool_cleanup_file_t  *cf;    for (c = p->cleanup; c; c = c->next) {        if (c->handler == ngx_pool_cleanup_file) {            cf = c->data;            if (cf->fd == fd) {                c->handler(cf);                c->handler = NULL;                return;            }        }    }}// 释放文件描述符voidngx_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);    }}// 从文件系统删除文件,data 指针指向一个 ngx_pool_cleanup_file_t 类型的数据voidngx_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 0static 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;}

Nginx源码完全注释(7)ngx_palloc.h/ngx_palloc.c