日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

nginx源码分析—数组结构ngx_array_t

發布時間:2024/2/28 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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);??//接著分配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;??//設置內存池的last指針??
  • ????}??
  • ???
  • ????if?((u_char?*)?a?+sizeof(ngx_array_t)?==?p->d.last)?{??//接著銷毀數組頭??
  • ????????p->d.last?=?(u_char*)?a;??????????//設置內存池的last指針??
  • ????}??
  • }??
  • 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)?{??//數組數據區滿??
  • ???
  • ????????/*?the?arrayis?full?*/??
  • ???
  • ????????size?=?a->size?*a->nalloc;??//計算數組數據區的大小??
  • ???
  • ????????p?=?a->pool;??
  • ???
  • ????????if?((u_char?*)a->elts?+?size?==?p->d.last??//若內存池的last指針指向數組數據區的末尾??
  • ????????????&&p->d.last?+?a->size?<=?p->d.end)?//且內存池未使用的區域可以再分配一個size大小的小空間??
  • ????????{??
  • ????????????/*?
  • ?????????????*?the?array?allocation?is?the?lastin?the?pool?
  • ?????????????*?and?there?is?space?for?newallocation?
  • ?????????????*/??
  • ???
  • ????????????p->d.last?+=a->size;??//分配一個size大小的小空間(a->size為數組一個元素的大小)??
  • ????????????a->nalloc++;???????????//實際分配小空間的個數加1??
  • ???
  • ????????}?else?{??
  • ????????????/*?allocate?a?new?array?*/??
  • ???
  • ????????????new?=ngx_palloc(p,?2?*?size);??//否則,擴展數組數據區為原來的2倍??
  • ????????????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
  • /**?
  • ?*?ngx_array_t?test,?to?test?ngx_array_create,?ngx_array_push?
  • ?*/??
  • ??
  • #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的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。