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] ...
 *
 *  }
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章