Nginx原始碼完全註釋(2)ngx_array.h / ngx_array.c

鍾超發表於2012-09-09

Nginx原始碼完全註釋(2)ngx_array.h / ngx_array.c

  • 作者:柳大·Poechant(鍾超)
  • 郵箱:zhongchao.ustc#gmail.com(# -> @)
  • 部落格:Blog.CSDN.net/Poechant
  • 日期:August 15th, 2012

陣列標頭檔案ngx_array.h


#include <ngx_config.h>
#include <ngx_core.h>

struct ngx_array_s {
    void        *elts;
    ngx_uint_t   nelts;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *pool;
};

ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
void ngx_array_destroy(ngx_array_t *a);
void *ngx_array_push(ngx_array_t *a);
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);

// 初始化似乎沒什麼好說的
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    /*
     * set "array->nelts" before "array->elts", otherwise MSVC thinks
     * that "array->nelts" may be used without having been initialized
     */

    array->nelts = 0;
    array->size = size;
    array->nalloc = n;
    array->pool = pool;

    array->elts = ngx_palloc(pool, n * size);
    if (array->elts == NULL) {
        return NGX_ERROR;
    }

    return NGX_OK;
}

陣列原始檔ngx_array.c


#include <ngx_config.h>
#include <ngx_core.h>

/* 建立一個 Nginx 陣列,記憶體池地址為 p,元素個數為 n,每個元素大小為 size */
ngx_array_t *
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
    ngx_array_t *a;

    // 呼叫 ngx_palloc,從 記憶體池 p,為 Nginx 陣列 a 分配記憶體
    a = ngx_palloc(p, sizeof(ngx_array_t));
    if (a == NULL) {
        return NULL;
    }

    // 呼叫 ngx_palloc,為 Nginx 陣列 a 的 elts 分配記憶體,大小為 n * size
    a->elts = ngx_palloc(p, n * size);
    if (a->elts == NULL) {
        return NULL;
    }
    
    // 注意,上面是先分配定義結構區,再定義資料儲存區

    // 其他初始化項
    a->nelts = 0; // 已存元素數
    a->size = size; // 每個元素大小(位元組)
    a->nalloc = n; // 最大元素數
    a->pool = p; // 記憶體池地址

    return a;
}


void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    // 陣列 a 的記憶體池地址
    p = a->pool;

    // 陣列 a 的最大儲存區的末尾,到了記憶體池的已用區域的末尾(可用區的開頭)
    // 即表示記憶體池目前最後一段儲存的是一個陣列的儲存區
    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
        // 記憶體池已用區域末尾向前挪(每個元素大小 x 最大元素個數)位元組
        p->d.last -= a->size * a->nalloc; 
    }

    // 陣列 a 結構體所佔用記憶體的末尾,為記憶體池的可用區的開頭
    // 即表示記憶體池目前最後一段儲存的是一個陣列的結構體
    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
        p->d.last = (u_char *) a;
    }
    
    // 上面先剪掉資料儲存區,再剪掉定義結構區
}


void *
ngx_array_push(ngx_array_t *a)
{
    void        *elt, *new;
    size_t       size;
    ngx_pool_t  *p;

    // 陣列滿了,即已儲存元素數 nelts 已達到最大容納數 nalloc
    if (a->nelts == a->nalloc) {

        /* the array is full */
        // size 為陣列的最大容量(最大容納數 x 每個元素大小)
        size = a->size * a->nalloc;

        p = a->pool;

        // 陣列的資料儲存區的末尾,到達了記憶體池的已用區域的末尾
        // 且,記憶體池的已用區域末尾的下一個位置<=記憶體池的末尾,就是說記憶體池還有夠用的剩餘空間
        if ((u_char *) a->elts + size == p->d.last
            && p->d.last + a->size <= p->d.end)
        {
            /*
             * the array allocation is the last in the pool
             * and there is space for new allocation
             */

            // 分配一個元素,就得把 last 往下挪一個,即已用區域往下挪一個
            p->d.last += a->size;
            
            // 分配一個元素,且記憶體池沒滿,就得把“最大元素數”加1
            a->nalloc++;

        } else { // 記憶體池剩餘空間不夠
            /* allocate a new array */

            // 分配一個兩倍的空間(原來空間的兩倍)
            new = ngx_palloc(p, 2 * size);
            if (new == NULL) {
                return NULL;
            }

            // 把 a->elts 的東東拷貝到 new 裡,拷貝 size 位元組個資料
            ngx_memcpy(new, a->elts, size);
            a->elts = new; // 新地址
            a->nalloc *= 2; // 新最大容量
            
            // size 不變(最大容量,即單個元素大小 x 最大元素數)
            // pool 不變
            // nelts 已用元素數不變
        }
    }

    // elt 為已用資料區的末尾
    elt = (u_char *) a->elts + a->size * a->nelts;
    
    // 已存資料個數加 1
    a->nelts++;

    // 返回這個已用資料區的末尾(可用資料區的開頭,或者說是下一個元素可以用的位置)
    return elt;
}


void *
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
{
    void        *elt, *new;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *p;

    // 要放的 n 個元素所佔的總位元組數
    size = n * a->size;

    // 已存元素數 + 要存的 n 個元素 > 最大容量(最大元素數)
    if (a->nelts + n > a->nalloc) {

        /* the array is full */

        p = a->pool;

        // 陣列的資料儲存區的末尾,到達了記憶體池的已用區域的末尾
        // 且,記憶體池的已用區域末尾的下一個位置<=記憶體池的末尾,就是說記憶體池還有夠用的剩餘空間
        if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
            && p->d.last + size <= p->d.end)
        {
            /*
             * the array allocation is the last in the pool
             * and there is space for new allocation
             */

            // 分配 n 個元素,就得把 last 往後挪 size = n * a->size
            p->d.last += size;
            
            // 分配 n 個元素,且記憶體池沒滿,就得把“最大元素數(最大容量)”加 n
            a->nalloc += n;

        } else { // 記憶體池剩餘空間不夠
            /* allocate a new array */

            // 準備分配一個兩倍的空間,nalloc是新空間的大小
            // (如果原來最大容量大,則分配原來空間的兩倍;如果新要的n個元素更多,則分配n的兩倍)
            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);

            // 分配新空間
            new = ngx_palloc(p, nalloc * a->size);
            if (new == NULL) {
                return NULL;
            }

            // 把老空間的東東,拷貝到新空間
            ngx_memcpy(new, a->elts, a->nelts * a->size);
            
            // elts 新空間地址
            a->elts = new;
            
            // nalloc 陣列最大容量
            a->nalloc = nalloc;
        }
    }

    // 要放入的 n 個元素的起始位置
    elt = (u_char *) a->elts + a->size * a->nelts;
    
    // 已用元素數加 n
    a->nelts += n;

    // 返回n個東東的位置
    return elt;
}

Reference

  1. http://blog.csdn.net/v_july_v/article/details/7040425
  2. http://www.cnblogs.com/sld666666/archive/2010/06/27/1766255.html
  3. http://www.cnblogs.com/jzhlin/archive/2012/06/05/Nginx_pool.html
  4. http://code.google.com/p/nginxsrp/wiki/NginxCodeReview#ngx的記憶體池

-

轉載請註明來自柳大Poechant(鍾超Michael)的CSDN部落格:

鍾超Michael的部落格:Blog.CSDN.net/Poechant

鍾超Michael的微博:鍾超Michael的新浪微博

-

相關文章