大佬連結: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中。