nginx源码分析—数组结构ngx_array_t

数组实现文件:文件:./src/core/ngx_array.h/.c

1.数组结构

struct ngx_array_s {
    void        *elts;        //数组数据区起始位置
    ngx_uint_t   nelts;       //实际存放的元素个数
    size_t       size;        //每个元素的大小
    ngx_uint_t   nalloc;      //数组分配的空间个数,即实际饭分配的小空间个数
    ngx_pool_t  *pool;        //该数组在内存中的分配
};

2.数组的基本操作(5个)

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)

2.1创建数组

创建数组的操作实现过程,首先分配数组头(20B),然后分配数组数据区,两次分配均在传入的内存池(pool指向的内存池)中进行。然后简单初始化数组头并返回数组头的起始位置。( 分配分两个阶段完成,注意和释放过程对应
ngx_array_t *
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
    ngx_array_t *a;

    a = ngx_palloc(p, sizeof(ngx_array_t));   //从内存中分配数组头
    if (a == NULL) {
        return NULL;
    }

    a->elts = ngx_palloc(p, n * size);        //分配大小为*size的内存作为数组数据区
    if (a->elts == NULL) {
        return NULL;
    }

    a->nelts = 0;                         //初始化
    a->size = size;
    a->nalloc = n;
    a->pool = p;

    return a;                             //返回内存起始位置
}

2.2数组销毁

销毁数组的操作实现过程,包括销毁数组数据区和数组头。这里的销毁动作实际上就是修改内存池的last指针,并没有调用free等释放内存的操作,显然,这种维护效率是很高的。
void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    p = a->pool;

    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {    
        p->d.last -= a->size * a->nalloc;               //释放数组的数据区,只是修改内存池的last指针
    }

    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
        p->d.last = (u_char *) a;                       //释放数组头, 再次修改内存池的last指针
    }
}

2.3添加元素到数组

向数组添加元素的操作有两个,ngx_array_push和ngx_array_push_n,分别添加一个和多个元素。

但实际的添加操作并不在这两个函数中完成,例如ngx_array_push返回可以在该数组数据区中添加这个元素的位置,ngx_array_push_n则返回可以在该数组数据区中添加n个元素的起始位置,而添加操作即在获得添加位置之后进行

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

    if (a->nelts == a->nalloc) {            //数据区已满

        /* the array is full */

        size = a->size * a->nalloc;        //数组当前可用数据区大小

        p = a->pool;             //指向当前内存池

        if ((u_char *) a->elts + size == p->d.last    //条件:内存池的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
             */

            p->d.last += a->size;  //last指针后移一位
            a->nalloc++;   //数组元素总数+1

        } else {
            /* allocate a new array */

            new = ngx_palloc(p, 2 * size);     //重新分配2倍空间
            if (new == NULL) {
                return NULL;
            }
            ngx_memcpy(new, a->elts, size);     //拷贝原来的数据
            a->elts = new;              //更新数组数据区指针
          a->nalloc *= 2;       //更新总容量
        }
    }
    elt = (u_char *) a->elts + a->size * a->nelts;//没满,直接后移指
    a->nelts++;     //总数+1
    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;

    size = n * a->size;

    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
             */

            p->d.last += size;
            a->nalloc += n;

        } else {
            /* allocate a new array */

            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);
            a->elts = new;
            a->nalloc = nalloc;
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts += n;

    return elt;
}
测试demo
#include <stdio.h>
#include "ngx_config.h"
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_array.h"

volatile ngx_cycle_t*   ngx_cycle;

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
            const char *fmt, ...)
{
}

void dump_pool(ngx_pool_t* pool)
{
        while(pool)
        {
                printf("pool = 0x%x\n", pool);
                printf("  .d\n");
                printf(".last = 0x%x\n", pool->d.last);
                printf(".end = 0x%x\n", pool->d.end);
                printf(".next = 0x%x\n", pool->d.next);
                printf(".failed = %d\n", pool->d.failed);

                printf(".max = %d\n", pool->max);
                printf(".current = 0x%x\n", pool->current);
                printf(".chain = 0x%x\n", pool->chain);
                printf(".large = 0x%x\n", pool->large);
                printf(".cleanup = 0x%x\n", pool->cleanup);
                printf(".log = 0x%x\n", pool->log);
                printf("available pool memory = 0x%x\n\n", pool->d.end - pool->d.last);
                pool = pool->d.next;
        }
}
void dump_array(ngx_array_t *a)
{
        if(a)
        {
                printf("array = 0x%x\n", a);
                printf("        .elts = 0x%x\n", a->elts);
                printf("        .nelts = %d\n", a->nelts);
                printf("        .size = %d\n", a->size);
                printf("        .nalloc = %d\n", a->nalloc);
                printf("        .pool = 0x%x\n", a->pool);

                printf("elements:    ");
                int* ptr = (int*)(a->elts);
                for(; ptr < (int*)(a->elts + a->nalloc*a->size);)
                {
                        printf("0x%x    ", *ptr++);
                }
                printf("\n");
        }
}
int main()
{
        ngx_pool_t      *pool;
        int     i;

        printf("*************************************************\n");
        printf("create a new pool:\n");
        printf("*************************************************\n");

        pool = ngx_create_pool(1024, NULL);
        dump_pool(pool);

        printf("-------------------------------------------------\n");
        printf("alloc an array from the pool:\n");
        printf("-------------------------------------------------\n");

        ngx_array_t     *a = ngx_array_create(pool, 10, sizeof(int));
        dump_pool(pool);
        for(i = 0; i < 1000; i++)
        {
                int *ptr = ngx_array_push(a);
                *ptr = i + 1;
        }
        dump_array(a);

        size_t  iLen = sizeof(ngx_array_t);
        printf("sizeof(ngx_array_t) == == 0x%x\n", iLen);

        ngx_array_destroy(a);
        ngx_destroy_pool(pool);

        return 0;
}
测试结果
*************************************************
create a new pool:
*************************************************
pool = 0x9b6b020
  .d
.last = 0x9b6b048
.end = 0x9b6b420
.next = 0x0
.failed = 0
.max = 984
.current = 0x9b6b020
.chain = 0x0
.large = 0x0
.cleanup = 0x0
.log = 0x0
available pool memory = 0x3d8

-------------------------------------------------
alloc an array from the pool:
-------------------------------------------------
pool = 0x9b6b020
  .d
.last = 0x9b6b084
.end = 0x9b6b420
.next = 0x0
.failed = 0
.max = 984
.current = 0x9b6b020
.chain = 0x0
.large = 0x0
.cleanup = 0x0
.log = 0x0
available pool memory = 0x39c

array = 0x9b6b048
	.elts = 0x9b6b05c
	.nelts = 10
	.size = 4
	.nalloc = 10
	.pool = 0x9b6b020
elements:    0x1	0x2	0x3	0x4	0x5	0x6	0x7	0x8	0x9	0xa	
sizeof(ngx_array_t) == == 0x14
sizeof(ngx_pool_t)  ===  == 0x28
sizeof(ngx_pool_data_t) ===  === 0x10


你可能感兴趣的:(nginx源码分析—数组结构ngx_array_t)