ngx_list_t是nginx封裝鍊錶的容器,其原始碼位於:
宣告:~/nginx/src/core/ngx_list.h
定義:~/nginx/src/core/ngx_list.c
在nginx中使用頻繁,例如http頭部就是用ngx_list_t儲存的。
nginx的鍊錶(頭)結構為ngx_list_t,鍊錶節點結構為ngx_list_part_t,定義如下。
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s ;
typedef struct ngx_list_t;
ngx_list_t的結構示意如下:
可以看到這種設計非常巧妙。ngx_list_t是乙個鍊錶容器,而鍊錶中的元素又是乙個陣列。事實上,ngx_list_part_t陣列中的元素才是使用者想要儲存的東西,ngx_list_t能夠容納的元素數量由ngx_list_part_t陣列元素的個數與每個陣列所能容納的元素相乘得到。這樣設計的好處在於:
1.鍊錶中儲存的元素是靈活的,可以是任意一種資料結構。
2.鍊錶占用的記憶體由ngx_list_t管理,他已經分配好了(由圖可知是一塊連續記憶體)。
3.元素訪問高效(陣列下標即可訪問)。
主要有三個操作,建立、初始化和插入元素,對應下述三個函式:
//建立鍊錶
ngx_list_t*ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
//初始化鍊錶
static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool,
ngx_uint_tn, size_t size);
//新增元素
void*ngx_list_push(ngx_list_t *l)
他們的實現都很簡單,本文只分析建立鍊錶和新增元素操作。
2.1建立鍊錶
建立鍊錶的操作實現如下,首先分配煉表頭(28b),然後分配頭節點(即煉表頭中包含的part)資料區,兩次分配均在傳入的記憶體池(pool指向的記憶體池)中進行。然後簡單初始化煉表頭並返回煉表頭的起始位置。
ngx_list_t *
ngx_list_create(ngx_pool_t*pool, ngx_uint_t n, size_t size)
list->part.elts =ngx_palloc(pool, n * size); //接著分配n*size大小的區域作為鍊錶資料區
if (list->part.elts == null)
list->part.nelts = 0; //初始化
list->part.next = null;
list->last = &list->part;
list->size = size;
list->nalloc = n;
list->pool = pool;
return list; //返回煉表頭的起始位置
}2.2插入元素
新增元素操作實現如下,同nginx陣列實現類似,其實際的新增操作並不在該函式中完成。函式ngx_list_push返回可以在該鍊錶資料區中放置元素(元素可以是1個或多個)的位置,而新增操作即在獲得新增位置之後進行,如後文的例子。
也就是說,push操作返回待插入元素在list分配的記憶體區的位址。
void *
ngx_list_push(ngx_list_t*l)
last->elts =ngx_palloc(l->pool, l->nalloc * l->size);//分配該節點(part)的資料區
if (last->elts == null)
last->nelts = 0;
last->next = null;
l->last->next =last; //將分配的list part插入鍊錶
l->last = last; //並修改list頭的last指標
} //last->elts為首位址
elt = (char *)last->elts + l->size * last->nelts; //計算下乙個資料在鍊錶資料區中的位置
last->nelts++; //實際存放的資料個數加1
return elt; //返回該位置
}#include
#include
#include "ngx_config.h"
#include "nginx.h"
#include "ngx_conf_file.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_list.h"
#define n 5
volatile ngx_cycle_t *ngx_cycle;
#if 1
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log,
ngx_err_t err, const char *fmt, ...)
void print_list(ngx_list_t *l)
p = p->next;
if(p)
pstr=p->elts;
} printf("-------------------------------\n");
} #endif
int main()
print_list(l);
printf("unused memory size is %d\n", (ngx_uint_t)(pool->d.end -
pool->d.last) );
ngx_destroy_pool(pool);
#endif
return 0;
}#makefile
cc=gcc
cflags = -g -wall -wextra
targets=ngx_list_test
targets_file=ngx_list_test.c
dir=$/nginx/nginx-1.0.15
all:$(targets)
clean:
rm -f $(targets) *.o
include=-i $/src/core/ -i $(dir)/objs/ -i $(dir)/src/event -i $(dir)/src/event/modules -i $(dir)/src/os/unix
ngx_obj = $(dir)/objs/src/core/ngx_palloc.o $(dir)/objs/src/core/ngx_string.o $(dir)/objs/src/os/unix/ngx_alloc.o $(dir)/objs/src/core/ngx_list.o
$(targets):$
$(cc) $(cflags) $ $(include) $(ngx_obj) -o $@
測試結果
Nginx原始碼分析之ngx array t
ngx array t是乙個順序容器,類似於stl中的vector可以動態擴容。原始碼位置 nginx src core ngx array.h nginx src core ngx array.c typedef struct ngx array s ngx array t struct ngx ...
nginx 原始碼分析
近期準備研究一下nginx原始碼,此處記錄一下。計畫 1 了解evan miller 的文章 2 了解nginx的組織架構 3 了解nginx的基本資料結構 4 熟悉nginx的主要module及執行機制,主要是core http event os 5 簡單的module開發及測試 一 準備 為了方...
nginx原始碼分析 從原始碼看nginx框架總結
nginx原始碼總結 1 中沒有特別繞特別彆扭的編碼實現,從變數的定義呼叫函式的實現封裝,都非常恰當,比如從函式命名或者變數命名就可以看出來定義的大體意義,函式的基本功能,再好的架構實現在編碼習慣差的人實現也會黯然失色,如果透徹理解 的實現,領悟架構的設計初衷,覺得每塊 就想經過耐心雕琢一樣,不僅僅...