zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/breg/p/4043593.html
Copyright © 2011-2022 走看看