nginx原始碼分析之ngx list

2021-12-29 21:24:57 字數 3860 閱讀 8353

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 中沒有特別繞特別彆扭的編碼實現,從變數的定義呼叫函式的實現封裝,都非常恰當,比如從函式命名或者變數命名就可以看出來定義的大體意義,函式的基本功能,再好的架構實現在編碼習慣差的人實現也會黯然失色,如果透徹理解 的實現,領悟架構的設計初衷,覺得每塊 就想經過耐心雕琢一樣,不僅僅...