天天看點

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 = ;

    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(, NULL);//建立一個記憶體池,容量為1024B
           

建立完pool,再建立連結清單容器:

ngx_list_t *list = ngx_list_create(pool, , sizeof(int));//配置設定*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, );
    }
#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 - )) & ~((uintptr_t) a - ))
           

了解一下

#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 = ;
    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中。

繼續閱讀