> 文档中心 > Nginx源码阅读:ngx_list_t 链表

Nginx源码阅读:ngx_list_t 链表

Nginx源码阅读:ngx_list_t 链表

  • 一、Nginx中链表(ngx_list_t)的结构图
  • 二、源码阅读
    • 1、`ngx_list_part_s`
    • 2、`ngx_list_t`
    • 3、`ngx_list_create`
    • 4、`ngx_list_init`
    • 5、`ngx_list_push`

一、Nginx中链表(ngx_list_t)的结构图

Nginx源码阅读:ngx_list_t 链表

ngx_list_t作为一个链表的结构体,里面是一些链表的信息,ngx_list_part_t是链表的节点。
ngx中的链表并不是将内存简单串起来,而是将内存组织成块(chunck,在ngx中叫part),然后将这些块通过链表串起来。
每个块划分为nalloc片区域,每片区域的大小为size,因此一个chunck的大小为n*nalloc
一个chunck中已分配的区域片数为nelts

二、源码阅读

1、ngx_list_part_s

//一个chunk块(part)struct ngx_list_part_s {    void      *elts;  //数据区域首地址的指针    ngx_uint_t nelts; //已分配的数据区域的个数    ngx_list_part_t  *next;  //下一个chunck(part)};

2、ngx_list_t

链表的结构体,包含一些链表的信息,用于将(chunck)part组织起来

//链表,用来组织chunk块typedef struct {    ngx_list_part_t  *last;     //最后一块chunck    ngx_list_part_t   part;     //第一块chunck    size_t     size;     //一个片的大小为size(一个chunck分为nalloc片,那么一个chunck大小为nalloc*size)    ngx_uint_t nalloc;   //一个chunck划分成nalloc片区域    ngx_pool_t*pool;     //所属的内存池} ngx_list_t;

3、ngx_list_create

创建一个链表,首先要从内存池中分配一块数据给list结构体,然后再交给ngx_list_init去初始化具体信息,和分配数据区域空间。

ngx_list_t *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));//从内存池分配一块数据,用于存储list结构体    if (list == NULL) { return NULL;    }    if (ngx_list_init(list, pool, n, size) != NGX_OK) {//初始化 return NULL;    }    return list;}

4、ngx_list_init

初始化list结构体的信息,并分配一块chunck

static ngx_inline ngx_int_tngx_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);//创建一块chunck的数据区域,大小为 片数量*每个片的空间大小    if (list->part.elts == NULL) { return NGX_ERROR;    }    list->part.nelts = 0;//初始化的时候,还没将空间使用,因此是0    list->part.next = NULL;    list->last = &list->part;//初始化的时候最后一块chunck就是第一块    list->size = size;//初始化的数据大小    list->nalloc = n;    list->pool = pool;//所属的内存池    return NGX_OK;}

5、ngx_list_push

通过list来获取一块空间的首地址。

取一块数据为什么叫push呢?因为数据是通过list组织起来的,分配的空间通过list来组织,也就是要push到list中的。

void *ngx_list_push(ngx_list_t *l){    void      *elt;    ngx_list_part_t  *last;    last = l->last;//list中最后一个chunck    if (last->nelts == l->nalloc) {//如果最后一块chunck中的片已经全部使用完了,那么就要新创建一个chunck,以及空间大小 /* the last part is full, allocate a new list part */ last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));//创建chunck头的空间 if (last == NULL) {     return NULL; } last->elts = ngx_palloc(l->pool, l->nalloc * l->size);//创建chunck数据空间 if (last->elts == NULL) {     return NULL; } last->nelts = 0;//已使用的片的数量为0 last->next = NULL; l->last->next = last;//新创建的chunck为最后一个chunk l->last = last;    }    elt = (char *) last->elts + l->size * last->nelts;//返回可以使用的内存空间地址(根据当前chunck中已经使用的片数量)    last->nelts++;//当前chunck中使用的片数量+1    return elt;}