• 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;
    }
    
    // 销毁内存池 pool
    void
    ngx_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;
            }
        }
    }
    
    // 重置内存池
    void
    ngx_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_t
    ngx_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,实现分配内存并初始化为 0
    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;
    }
    
    // 向 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 = 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;
    }
    
    // 查找指定的 fd,且其 handler 为 ngx_pool_cleanup_file,执行相应动作
    // 这里面有一个遍历的操作
    void
    ngx_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;
                }
            }
        }
    }
    
    // 释放文件描述符
    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);
        }
    }
    
    // 从文件系统删除文件,data 指针指向一个 ngx_pool_cleanup_file_t 类型的数据
    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;
    }
    
    
  • 相关阅读:
    51nod 1117 聪明的木匠:哈夫曼树
    51nod 1010 只包含因子2 3 5的数
    51nod 2636 卡车加油
    51nod 2989 组合数
    51nod 2652 阶乘0的数量 V2
    51nod 1103 N的倍数
    51nod 2489 小b和灯泡
    51nod 1003 阶乘后面0的数量
    51nod 2122 分解质因数
    javascript中的setter和getter
  • 原文地址:https://www.cnblogs.com/breg/p/4043593.html
Copyright © 2020-2023  润新知