nginx源码初读(6)--让烦恼从数据结构开始(ngx_list)

nginx自定的list跟我们常见的list是不太一样的,不同点就在于它的节点,它的节点不像我们常见的list的节点,只能存放一个元素,ngx_list_t的节点实际上是一个固定大小的数组。

在初始化的时候,我们需要设定元素需要占用的空间大小,每个节点数组的容量大小。在添加元素到这个list里面的时候,会在最尾部的节点里的数组上添加元素,如果这个节点的数组存满了,再增加新的节点。

我们看一下数据结构定义:

typedef struct ngx_list_part_s  ngx_list_part_t;
struct ngx_list_part_s {
    void             *elts;        // 当前节点内存的起始位置(每个节点内存大小是size*nalloc)
    ngx_uint_t        nelts;       // 当前节点中已存放元素的数量
    ngx_list_part_t  *next;        // next节点
};

typedef struct {
    ngx_list_part_t  *last;        // 指向链表中最后一个节点,这个存在的好处是添加元素很方便啊
    ngx_list_part_t   part;        // 链表头节点,注意这里不是指针,而是list的一部分
    size_t            size;        // 单个元素的大小
    ngx_uint_t        nalloc;      // 每一个节点的容量(能存储nalloc个元素)
    ngx_pool_t       *pool;        // list所在的内存池
} ngx_list_t;

创建链表函数:

ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
/* 创建很简单,跟array一样,先分配好结构体的内存,再调用init进行初始化并分配节点elts的内存 
   create时设定nalloc=n, size=size */

static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size);
/* 如果ngx_list_t类型的变量不是通过调用函数ngx_list_create创建的(比如某结构体中有个ngx_list),
   就必须调用此函数去初始化,否则往这个list里追加元素会引发不可预知的行为,亦或程序会崩溃 */

添加元素函数:

void *
ngx_list_push(ngx_list_t *l)
{
    void             *elt;
    ngx_list_part_t  *last;
    last = l->last;
    // 如果当前节点满员了,申请下一个节点出来,还是先结构体后内存空间
    //(有个问题,如果结构出来了内存区拿不到岂不是浪费空间了又,好吧无所谓了,已经出错了这时)
    if (last->nelts == l->nalloc) {    
        last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
        if (last == NULL) {
            return NULL;
        }
        last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
        if (last->elts == NULL) {
            return NULL;
        }
        last->nelts = 0;
        last->next = NULL;
        l->last->next = last;     // 重定向last
        l->last = last;
    }

    elt = (char *) last->elts + l->size * last->nelts;  
    return elt;
}

对了,再加一段代码,这是nginx的源文件中被注释掉的,我感觉是作者留给我们遍历list的示范:

/*
 *  
 *  the iteration through the list:
 *  
 *  part = &list.part;
 *  data = part->elts;
 *
 *  for (i = 0 ;; i++) {
 *      
 *      if (i >= part->nelts) {
 *          if (part->next == NULL) {
 *              break;
 *          }
 *
 *          part = part->next;
 *          data = part->elts;
 *          i = 0;
 *      }
 *
 *      ...  data[i] ...
 *
 *  }
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章