nginx数据结构

大佬链接:http://blog.csdn.net/livelylittlefish/article/details/6599065
http://blog.csdn.net/livelylittlefish/article/details/6586946

ngx_list_t是nginx封装的链表容器

typedef struct ngx_list_part_s  ngx_list_part_t;

struct ngx_list_part_s {
    void             *elts;//指向该节点实际的数据区
    ngx_uint_t        nelts;//该节点实际存放的元素个数
    ngx_list_part_t  *next;//指向下个节点
};//ngx_list_part_t


typedef struct {
    ngx_list_part_t  *last;//指向链表最后一个节点
    ngx_list_part_t   part;//链表的首个数组元素
    size_t            size;//每个实际存放元素大小
    ngx_uint_t        nalloc;//实际存放元素的个数
    ngx_pool_t       *pool;//指向该链表所分配的内存池首地址
} ngx_list_t;

//其中,sizeof(ngx_list_t)=28B,sizeof(ngx_list_part_t)=12B

由ngx_list_t结构体中的pool成员指向创建该ngx_list_t链表的内存池首地址,是什么意思?
是指ngx_list_t结构体存储在由pool指向的内存池中,因此,要在创建ngx_list_t前先创建pool指向的内存池。内存池的结构体如下:

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;//指向ngx_pool_t结构体尾部
    u_char               *end;//指向创建的pool内存池尾部
    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;
};//ngx_pool_t

其中,sizeof(ngx_pool_data_t)=16B,sizeof(ngx_pool_t)=40B
创建内存池(ngx_palloc.c):

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;//max最大不超过4095B?

    p->current = p;
    p->chain = NULL;
    p->large = NULL;
    p->cleanup = NULL;
    p->log = log;

    return p;
}

创建内存池例子:

    ngx_pool_t *pool;     
    printf("create a new pool:\n");   
    pool = ngx_create_pool(1024, NULL);//创建一个内存池,容量为1024B

创建完pool,再创建链表容器:

ngx_list_t *list = ngx_list_create(pool, 5, sizeof(int));//分配5*sizeof(int)容量给list

ngx_list_create:

ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    ngx_list_t  *list;

    list = ngx_palloc(pool, sizeof(ngx_list_t));//分配28B内存给ngx_list_t
    if (list == NULL) {
        return NULL;
    }

    if (ngx_list_init(list, pool, n, size) != NGX_OK) {//初始化链表,分配实际容量n*size给list
        return NULL;
    }

    return list;
}

ngx_palloc:

void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {//分配内存容量小于内存池实际容量
        return ngx_palloc_small(pool, size, 1);
    }
#endif

    return ngx_palloc_large(pool, size);
}

ngx_palloc_small:

static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
    u_char      *m;
    ngx_pool_t  *p;

    p = pool->current;//内存池首地址

    do {
        m = p->d.last;//内存池实际容量首地址

        if (align) {//对齐
            m = ngx_align_ptr(m, NGX_ALIGNMENT);
        }

        if ((size_t) (p->d.end - m) >= size) {
            p->d.last = m + size;//size为ngx_list_t被分配的内存池容量

            return m;
        }

        p = p->d.next;

    } while (p);

    return ngx_palloc_block(pool, size);
}

http://blog.csdn.net/niitlcj/article/details/9311189
ngx_align_ptr:

#ifndef NGX_ALIGNMENT
#define NGX_ALIGNMENT   sizeof(unsigned long)    /* platform word */
#endif

#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))

理解一下
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
a是2的幕(如NGX_ALIGNMENT),因此,a的二进制形式,假设第n位为1,因此第0~n-1位为0,高于n的位皆为0,即0…010…0。因此,a-1为0…001…1,~(a-1)为1…110…0。
(d)+(a-1)必然 >= a ,当d<=a时,(d)+(a-1)的第n位必然为1,所以&(~(a-1))后,为0…010…0,即a;当d>a时,((d)+(a-1)) & ~(a - 1)将会是a的整数k倍,且d<=k*a。因此,实现内存对齐。

这种计算地址或者长度对齐,取整的宏还是很有用的。cpu访问对齐的数据较快,不对齐的的int之类的,有可能区要多次内存访问才能取到值。

向上取整倍数,ngx_align内存对齐的宏,对于a,传入CPU的二级cache的line大小,通过ngx_cpuinf函数,可以获得ngx_cacheline_size的大小,一般intel为64或128

计算宏ngx_align(1, 64)=64,只要输入d<64,则结果总是64,如果输入d=65,则结果为128,以此类推。

ngx_list_init:

static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    list->part.elts = ngx_palloc(pool, n * size);
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

    list->part.nelts = 0;
    list->part.next = NULL;
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return NGX_OK;
}

可以看到,ngx_list_init初始化ngx_list_t时,把n*size的内存池容量首地址放在part.elts中。

猜你喜欢

转载自blog.csdn.net/linda_ds/article/details/76228386
今日推荐