生活随笔
收集整理的這篇文章主要介紹了
nginx源码分析—数组结构ngx_array_t
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Content
0.?序
1.?數組結構
1.1 ngx_array_t結構
1.2 ngx_array_t的邏輯結構
2.?數組操作
2.1?創建數組
2.2?銷毀數組
2.3?添加1個元素
3.?一個例子
3.1?代碼
3.2?如何編譯
3.3?運行結果
4.?小結
0. 序
本文開始介紹nginx的容器,先從最簡單的數組開始。
數組實現文件:文件:./src/core/ngx_array.h/.c。.表示nginx-1.0.4代碼目錄,本文為/usr/src/nginx-1.0.4。
1. 數組結構
1.1 ngx_array_t結構
nginx的數組結構為ngx_array_t,定義如下。
[cpp]?view plaincopy
struct?ngx_array_s?{?? ????void????????*elts;?????? ????ngx_uint_t???nelts;????? ????size_t???????size;?????? ????ngx_uint_t???nalloc;???? ????ngx_pool_t??*pool;?????? };?? ??? typedef?struct?ngx_array_s??ngx_array_t;??
sizeof(ngx_array_t)=20。由其定義可見,nginx的數組也要從內存池中分配。將分配nalloc個大小為size的小空間,實際分配的大小為(nalloc * size)。詳見下文的分析。
1.2 ngx_array_t的邏輯結構
ngx_array_t結構引用了ngx_pool_t結構,因此本文參考nginx-1.0.4源碼分析—內存池結構ngx_pool_t及內存管理一文畫出相關結構的邏輯圖,如下。注:本文采用UML的方式畫出該圖。?
?
?2. 數組操作
數組操作共有5個,如下。
[cpp]?view plaincopy
?? ngx_array_t*ngx_array_create(ngx_pool_t?*p,?ngx_uint_t?n,?size_t?size);?? ??? ?? voidngx_array_destroy(ngx_array_t?*a);?? ??? ?? void*ngx_array_push(ngx_array_t?*a);?? void*ngx_array_push_n(ngx_array_t?*a,?ngx_uint_t?n);?? ??? ?? staticngx_inline?ngx_int_t?? ngx_array_init(ngx_array_t*array,?ngx_pool_t?*pool,?ngx_uint_t?n,?size_t?size)??
因實現都很簡單,本文簡單分析前3個函數。
2.1 創建數組
創建數組的操作實現如下,首先分配數組頭(20B),然后分配數組數據區,兩次分配均在傳入的內存池(pool指向的內存池)中進行。然后簡單初始化數組頭并返回數組頭的起始位置。
[cpp]?view plaincopy
ngx_array_t*?? ngx_array_create(ngx_pool_t*p,?ngx_uint_t?n,?size_t?size)?? {?? ????ngx_array_t?*a;?? ??? ????a?=?ngx_palloc(p,sizeof(ngx_array_t));???? ????if?(a?==?NULL)?{?? ????????return?NULL;?? ????}?? ??? ????a->elts?=?ngx_palloc(p,n?*?size);???? ????if?(a->elts?==?NULL)?{?? ????????return?NULL;?? ????}?? ??? ????a->nelts?=?0;?????? ????a->size?=?size;?? ????a->nalloc?=?n;?? ????a->pool?=?p;?? ??? ????return?a;???? }??
創建數組后內存池的物理結構圖如下。
?
?2.2 銷毀數組
銷毀數組的操作實現如下,包括銷毀數組數據區和數組頭。這里的銷毀動作實際上就是修改內存池的last指針,并沒有調用free等釋放內存的操作,顯然,這種維護效率是很高的。
[cpp]?view plaincopy
void?? ngx_array_destroy(ngx_array_t*a)?? {?? ????ngx_pool_t?*p;?? ??? ????p?=?a->pool;?? ??? ????if?((u_char?*)?a->elts+?a->size?*?a->nalloc?==?p->d.last)?{???? ????????p->d.last?-=a->size?*?a->nalloc;???? ????}?? ??? ????if?((u_char?*)?a?+sizeof(ngx_array_t)?==?p->d.last)?{???? ????????p->d.last?=?(u_char*)?a;???????????? ????}?? }??
2.3 添加1個元素
向數組添加元素的操作有兩個,ngx_array_push和ngx_array_push_n,分別添加一個和多個元素。
但實際的添加操作并不在這兩個函數中完成,例如ngx_array_push返回可以在該數組數據區中添加這個元素的位置,ngx_array_push_n則返回可以在該數組數據區中添加n個元素的起始位置,而添加操作即在獲得添加位置之后進行,如后文的例子。
[cpp]?view plaincopy
void?*?? ngx_array_push(ngx_array_t*a)?? {?? ????void???????*elt,?*new;?? ????size_t??????size;?? ????ngx_pool_t?*p;?? ??? ????if?(a->nelts?==a->nalloc)?{???? ??? ?????????? ??? ????????size?=?a->size?*a->nalloc;???? ??? ????????p?=?a->pool;?? ??? ????????if?((u_char?*)a->elts?+?size?==?p->d.last???? ????????????&&p->d.last?+?a->size?<=?p->d.end)??? ????????{?? ????????????? ? ? ?? ??? ????????????p->d.last?+=a->size;???? ????????????a->nalloc++;????????????? ??? ????????}?else?{?? ?????????????? ??? ????????????new?=ngx_palloc(p,?2?*?size);???? ????????????if?(new?==?NULL)?{?? ????????????????return?NULL;?? ????????????}?? ??? ????????????ngx_memcpy(new,a->elts,?size);?? ????????????a->elts?=?new;?? ????????????a->nalloc?*=?2;??????????????? ????????}?? ????}?? ??? ????elt?=?(u_char?*)a->elts?+?a->size?*?a->nelts;??? ????a->nelts++;???????????????????????????????????? ??? ????return?elt;?????? }??
由此可見,向數組中添加元素實際上也是在修該內存池的last指針(若數組數據區滿)及數組頭信息,即使數組滿了,需要擴展數據區內容,也只需要內存拷貝完成,并不需要數據的移動操作,這個效率也是相當高的。
下圖是向數組中添加10個整型元素后的一個例子。代碼可參考下文的例子。當然,數組元素也不僅限于例子的整型數據,也可以是其他類型的數據,如結構體等。
?
3. 一個例子
理解并掌握開源軟件的最好方式莫過于自己寫一些測試代碼,或者改寫軟件本身,并進行調試來進一步理解開源軟件的原理和設計方法。本節給出一個創建內存池并從中分配一個數組的簡單例子。
3.1代碼
[cpp]?view plaincopy
? ? ?? ?? #include?<stdio.h>?? #include?"ngx_config.h"?? #include?"ngx_conf_file.h"?? #include?"nginx.h"?? #include?"ngx_core.h"?? #include?"ngx_string.h"?? #include?"ngx_palloc.h"?? #include?"ngx_array.h"?? ?? volatile?ngx_cycle_t??*ngx_cycle;?? ?? void?ngx_log_error_core(ngx_uint_t?level,?ngx_log_t?*log,?ngx_err_t?err,?? ????????????const?char?*fmt,?...)?? {?? }?? ?? void?dump_pool(ngx_pool_t*?pool)?? {?? ????while?(pool)?? ????{?? ????????printf("pool?=?0x%x\n",?pool);?? ????????printf("??.d\n");?? ????????printf("????.last?=?0x%x\n",?pool->d.last);?? ????????printf("????.end?=?0x%x\n",?pool->d.end);?? ????????printf("????.next?=?0x%x\n",?pool->d.next);?? ????????printf("????.failed?=?%d\n",?pool->d.failed);?? ????????printf("??.max?=?%d\n",?pool->max);?? ????????printf("??.current?=?0x%x\n",?pool->current);?? ????????printf("??.chain?=?0x%x\n",?pool->chain);?? ????????printf("??.large?=?0x%x\n",?pool->large);?? ????????printf("??.cleanup?=?0x%x\n",?pool->cleanup);?? ????????printf("??.log?=?0x%x\n",?pool->log);?? ????????printf("available?pool?memory?=?%d\n\n",?pool->d.end?-?pool->d.last);?? ????????pool?=?pool->d.next;?? ????}?? }?? ?? void?dump_array(ngx_array_t*?a)?? {?? ????if?(a)?? ????{?? ????????printf("array?=?0x%x\n",?a);?? ????????printf("??.elts?=?0x%x\n",?a->elts);?? ????????printf("??.nelts?=?%d\n",?a->nelts);?? ????????printf("??.size?=?%d\n",?a->size);?? ????????printf("??.nalloc?=?%d\n",?a->nalloc);?? ????????printf("??.pool?=?0x%x\n",?a->pool);?? ?? ????????printf("elements:?");?? ????????int?*ptr?=?(int*)(a->elts);?? ????????for?(;?ptr?<?(int*)(a->elts?+?a->nalloc?*?a->size);?)?? ????????{?? ????????????printf("0x%x??",?*ptr++);?? ????????}?? ????????printf("\n");?? ????}?? }?? ?? int?main()?? {?? ????ngx_pool_t?*pool;?? ????int?i;?? ?? ????printf("--------------------------------\n");?? ????printf("create?a?new?pool:\n");?? ????printf("--------------------------------\n");?? ????pool?=?ngx_create_pool(1024,?NULL);?? ????dump_pool(pool);?? ?? ????printf("--------------------------------\n");?? ????printf("alloc?an?array?from?the?pool:\n");?? ????printf("--------------------------------\n");?? ????ngx_array_t?*a?=?ngx_array_create(pool,?10,?sizeof(int));?? ????dump_pool(pool);?? ?? ????for?(i?=?0;?i?<?10;?i++)?? ????{?? ????????int?*ptr?=?ngx_array_push(a);?? ????????*ptr?=?i?+?1;?? ????}?? ?? ????dump_array(a);?? ?? ????ngx_array_destroy(a);?? ????ngx_destroy_pool(pool);?? ????return?0;?? }??
3.2如何編譯
請參考nginx-1.0.4源碼分析—內存池結構ngx_pool_t及內存管理一文。本文編寫的makefile文件如下。
[plain]?view plaincopy
CXX?=?gcc?? CXXFLAGS?+=-g?-Wall?-Wextra?? ??? NGX_ROOT?=/usr/src/nginx-1.0.4?? ??? TARGETS?=ngx_array_t_test?? TARGETS_C_FILE=?$(TARGETS).c?? ??? CLEANUP?=?rm-f?$(TARGETS)?*.o?? ??? all:$(TARGETS)?? ??? clean:?? $(CLEANUP)?? ??? CORE_INCS?=-I.?\?? -I$(NGX_ROOT)/src/core?\?? -I$(NGX_ROOT)/src/event?\?? -I$(NGX_ROOT)/src/event/modules?\?? -I$(NGX_ROOT)/src/os/unix?\?? -I$(NGX_ROOT)/objs?\?? ??? NGX_PALLOC?=$(NGX_ROOT)/objs/src/core/ngx_palloc.o?? NGX_STRING?=$(NGX_ROOT)/objs/src/core/ngx_string.o?? NGX_ALLOC?=$(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o?? NGX_ARRAY?=$(NGX_ROOT)/objs/src/core/ngx_array.o?? ??? $(TARGETS):$(TARGETS_C_FILE)?? $(CXX)?$(CXXFLAGS)?$(CORE_INCS)?$(NGX_PALLOC)?$(NGX_STRING)$(NGX_ALLOC)?$(NGX_ARRAY)?$^?-o?$@??
3.3運行結果
[plain]?view plaincopy
#?./ngx_array_t_test?? --------------------------------?create?a?new?pool:?? --------------------------------?pool?=?0x860b020?.d?.last?=?0x860b048?? ????.end?=?0x860b420?? ????.next?=?0x0?? ????.failed?=?0?.max?=?984?? ??.current?=?0x860b020?? ??.chain?=?0x0?? ??.large?=?0x0?? ??.cleanup?=?0x0?? ??.log?=?0x0?available?pool?memory?=?984?? --------------------------------?alloc?an?array?from?the?pool:?? --------------------------------?pool?=?0x860b020?.d?.last?=?0x860b084?? ????.end?=?0x860b420?? ????.next?=?0x0?? ????.failed?=?0?.max?=?984?? ??.current?=?0x860b020?? ??.chain?=?0x0?? ??.large?=?0x0?? ??.cleanup?=?0x0?? ??.log?=?0x0?available?pool?memory?=?924?? array?=?0x860b048?.elts?=?0x860b05c?? ??.nelts?=?10?? ??.size?=?4?? ??.nalloc?=?10?? ??.pool?=?0x860b020?elements:?0x1??0x2??0x3??0x4??0x5??0x6??0x7??0x8??0x9??0xa????
該例子中內存池和數組的(內存)物理結構可參考2.3節的圖。
4. 小結
本文針對nginx-1.0.4的容器——數組結構進行了較為全面的分析,包括數組相關數據結構,數組的創建、銷毀,以及向數組中添加元素等。最后通過一個簡單例子向讀者展示nginx數組的創建、添加元素和銷毀操作,同時借此向讀者展示編譯測試代碼的方法。
敬請關注后續的分析。謝謝!
Reference
Nginx代碼研究計劃?(RainX1982)
nginx-1.0.4源碼分析—內存池結構ngx_pool_t及內存管理?(阿波)
總結
以上是生活随笔為你收集整理的nginx源码分析—数组结构ngx_array_t的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。