Nginx源码分析(2)

Nginx有很多封装好的内部结构,实现诸如数组、链表、队列、哈希表等这样的容器。和STL一样,它们定义了自己的逻辑、功能及API。


ngx_array_t数组

ngx_array_t是nginx内部封装的使用ngx_pool_t对内存池进行分配的数组容器,其中的数据是在一整片内存区中连续存放的。更新数组时只能在尾部压入1个或多个元素,定义在nginx/src/core/ngx_array.h中。

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

其中elts指向数组元素所在的内存地址,nelts为实际元素个数,size是单个元素大小,nalloc为数组容量。

pool指向要使用的实例化的内存池。

  • 创建ngx_array_t数组
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;
    }
    if (ngx_array_init(a, p, n, size) != NGX_OK) {
        return NULL;
    }
    return a;
}

a是一个nginx数组指针,使用p指向的内存池分配内存。

static ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    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;
}

传进去实例化的内存池p、数组大小n和单个元素大小size。使用ngx_array_init来初始化数组,其中array->elts指向使用内存池p分配n * size大小的内存。

图示如下:

图片

  • 删除ngx_array_t数组
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;
    }
    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last)    {
        p->d.last = (u_char *) a;
    }

数组删除分为两步,第一个if中将标示数组空内存起始地址的last更新到上图的data(m)结尾;第二个if中将last更新到上图的ngx_pool_t结尾。

  • ngx_array_push增加元素
void *
ngx_array_push(ngx_array_t *a)
{
    void        *elt, *new;
    size_t       size;
    ngx_pool_t  *p;

    if (a->nelts == a->nalloc) {
        //数组已满
        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)
        {
            p->d.last += a->size;
            a->nalloc++;
        } else {
            //分配2倍的内存
            new = ngx_palloc(p, 2 * size);
            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++;
    return elt;
}

数组使用方法如下:

int main()
{
   int n;
   int* ele;
    //创建一个内存池
   ngx_pool_t* pool = ngx_create_pool(4000, NULL);
    //创建一个数组
   ngx_array_t* arr = ngx_array_create(pool, 10, sizeof(ngx_uint_t));;
   for (n=0; n < 5; n++) {
      ele = (int*) ngx_array_push(arr);
      *ele = n;
      printf("new element %d added\n", n);
    }
}

ngx_array_push(arr)在数组arr上新追加一个元素,并返回指向新元素的指针(ele)。需要把返回的指针使用类型转换,转换为具体的类型,然后再给新元素赋值*ele = n


##参考

https://code.google.com/p/nginxsrp/wiki/NginxCodeReview



Previous     Next
/
Published under (CC) BY-NC-SA in categories 服务器  tagged with