ngx_queue_t是nginx中的雙向鏈表,在nginx源碼目錄src/core下面的ngx_queue.h|c里面。它的原型如下:
[](http:// "點擊提交Issue,反饋你的意見...")
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
不同于教科書中將鏈表節點的數據成員聲明在鏈表節點的結構體中,ngx_queue_t只是聲明了前向和后向指針。在使用的時候,我們首先需要定義一個哨兵節點(對于后續具體存放數據的節點,我們稱之為數據節點),比如:
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_queue_t free;
接下來需要進行初始化,通過宏ngx_queue_init()來實現:
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_queue_init(&free);
ngx_queue_init()的宏定義如下:
#define ngx_queue_init(q) ? ? \
? ?(q)->prev = q; ? ? ? ? ? ?\
? ?(q)->next = q;
可見初始的時候哨兵節點的 prev 和 next 都指向自己,因此其實是一個空鏈表。ngx_queue_empty()可以用來判斷一個鏈表是否為空,其實現也很簡單,就是:
#define ngx_queue_empty(h) ? ?\
? ?(h == (h)->prev)
那么如何聲明一個具有數據元素的鏈表節點呢?只要在相應的結構體中加上一個 ngx_queue_t 的成員就行了。比如ngx_http_upstream_keepalive_module中的ngx_http_upstream_keepalive_cache_t:
[](http:// "點擊提交Issue,反饋你的意見...")
typedef struct {
ngx_http_upstream_keepalive_srv_conf_t *conf;
ngx_queue_t queue;
ngx_connection_t *connection;
socklen_t socklen;
u_char sockaddr[NGX_SOCKADDRLEN];
} ngx_http_upstream_keepalive_cache_t;
對于每一個這樣的數據節點,可以通過ngx_queue_insert_head()來添加到鏈表中,第一個參數是哨兵節點,第二個參數是數據節點,比如:
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_http_upstream_keepalive_cache_t cache;
ngx_queue_insert_head(&free, &cache.queue);
相應的幾個宏定義如下:
#define ngx_queue_insert_head(h, x) ? ? ? ? ? ? ? ? ? ? ? ? \
? ?(x)->next = (h)->next; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
? ?(x)->next->prev = x; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
? ?(x)->prev = h; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
? ?(h)->next = x#define ngx_queue_insert_after ? ngx_queue_insert_head#define ngx_queue_insert_tail(h, x) ? ? ? ? ? ? ? ? ? ? ? ? ?\
? ?(x)->prev = (h)->prev; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ?(x)->prev->next = x; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ?(x)->next = h; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ?(h)->prev = x
ngx_queue_insert_head()和ngx_queue_insert_after()都是往頭部添加節點,ngx_queue_insert_tail()是往尾部添加節點。從代碼可以看出哨兵節點的 prev 指向鏈表的尾數據節點,next 指向鏈表的頭數據節點。另外ngx_queue_head()和ngx_queue_last()這兩個宏分別可以得到頭節點和尾節點。
那假如現在有一個ngx_queue_t?[*](http://tengine.taobao.org/book/chapter_02.html#id4)q 指向的是鏈表中的數據節點的queue成員,如何得到ngx_http_upstream_keepalive_cache_t的數據呢? nginx提供了ngx_queue_data()宏來得到ngx_http_upstream_keepalive_cache_t的指針,例如:
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_http_upstream_keepalive_cache_t *cache = ngx_queue_data(q,
ngx_http_upstream_keepalive_cache_t,
queue);
也許您已經可以猜到ngx_queue_data是通過地址相減來得到的:
#define ngx_queue_data(q, type, link) ? ? ? ? ? ? ? ? ? ? ? ?\
? ?(type *) ((u_char *) q - offsetof(type, link))
另外nginx也提供了ngx_queue_remove()宏來從鏈表中刪除一個數據節點,以及ngx_queue_add()用來將一個鏈表添加到另一個鏈表。
- 上篇:nginx模塊開發篇
- nginx平臺初探
- 初探nginx架構
- nginx基礎概念
- connection
- request
- keepalive
- pipe
- lingering_close
- 基本數據結構
- ngx_str_t
- ngx_pool_t
- ngx_array_t
- ngx_hash_t
- ngx_hash_wildcard_t
- ngx_hash_combined_t
- ngx_hash_keys_arrays_t
- ngx_chain_t
- ngx_buf_t
- ngx_list_t
- ngx_queue_t
- nginx的配置系統
- 指令參數
- 指令上下文
- nginx的模塊化體系結構
- 模塊的分類
- nginx的請求處理
- handler模塊
- handler模塊簡介
- 模塊的基本結構
- 模塊配置結構
- 模塊配置指令
- 模塊上下文結構
- 模塊的定義
- handler模塊的基本結構
- handler模塊的掛載
- handler的編寫步驟
- 示例: hello handler 模塊
- handler模塊的編譯和使用
- 更多handler模塊示例分析
- http access module
- http static module
- http log module
- 過濾模塊
- 過濾模塊簡介
- 過濾模塊的分析
- upstream模塊
- upstream模塊
- upstream模塊接口
- memcached模塊分析
- 本節回顧
- 負載均衡模塊
- 配置
- 指令
- 鉤子
- 初始化配置
- 初始化請求
- peer.get和peer.free回調函數
- 本節回顧
- 其他模塊
- core模塊
- event模塊
- 模塊開發高級篇
- 變量
- 下篇:nginx原理解析篇
- nginx架構詳解
- nginx的源碼目錄結構
- nginx的configure原理
- 模塊編譯順序
- nginx基礎設施
- 內存池
- nginx的啟動階段
- 概述
- 共有流程
- 配置解析
- nginx的請求處理階段
- 接收請求流程
- http請求格式簡介
- 請求頭讀取
- 解析請求行
- 解析請求頭
- 請求體讀取
- 讀取請求體
- 丟棄請求體
- 多階段處理請求
- 多階段執行鏈
- POST_READ階段
- SERVER_REWRITE階段
- FIND_CONFIG階段
- REWRITE階段
- POST_REWRITE階段
- PREACCESS階段
- ACCESS階段
- POST_ACCESS階段
- TRY_FILES階段
- CONTENT階段
- LOG階段
- Nginx filter
- header filter分析
- body filter分析
- ngx_http_copy_filter_module分析
- ngx_http_write_filter_module分析
- subrequest原理解析
- https請求處理解析
- 附錄A 編碼風格
- 附錄B 常用API
- 附錄C 模塊編譯,調試與測試