Nginx原始碼完全註釋(4)ngx_queue.h / ngx_queue.c
Nginx原始碼完全註釋(4)ngx_queue.h / ngx_queue.c
- 作者:柳大·Poechant(鍾超)
- 郵箱:zhongchao.ustc#gmail.com(# -> @)
- 部落格:Blog.CSDN.net/Poechant
- 日期:August 17th, 2012
Nginx 中的佇列是有頭的,頭節點和佇列中的節點都是 ngx_queue_t。頭節點不用於儲存資料,資料是從頭節點的 next 節點開始儲存的。
佇列標頭檔案ngx_queue.h
#include <ngx_config.h>
#include <ngx_core.h>
#ifndef _NGX_QUEUE_H_INCLUDED_
#define _NGX_QUEUE_H_INCLUDED_
typedef struct ngx_queue_s ngx_queue_t;
// 佇列的節點,也直接表示佇列。注意這是一個雙向迴圈佇列
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
// 初始化佇列 q 所指向的指標,prev 和 next 都是自己
#define ngx_queue_init(q) \
(q)->prev = q; \
(q)->next = q
// 如果表 h == h 的上一個,那麼就是一個空佇列,其實用 next 也可以的
#define ngx_queue_empty(h) \
(h == (h)->prev)
// 向 h 後面插入一個 x
#define ngx_queue_insert_head(h, x) \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x
// 在後面插入 insert after,就是 insert head
#define ngx_queue_insert_after ngx_queue_insert_head
// 向 h 前面插入一個 x
#define ngx_queue_insert_tail(h, x) \
(x)->prev = (h)->prev; \
(x)->prev->next = x; \
(x)->next = h; \
(h)->prev = x
// h 表示佇列,第一個元素為 h->next
#define ngx_queue_head(h) \
(h)->next
// h 是頭,h 的上一個就是尾
#define ngx_queue_last(h) \
(h)->prev
#define ngx_queue_sentinel(h) \
(h)
// 返回節點 q 的下一個
#define ngx_queue_next(q) \
(q)->next
// 返回節點 q 的上一個
#define ngx_queue_prev(q) \
(q)->prev
#if (NGX_DEBUG)
// debug 模式下要把 x 的 prev、next 成員置為 0,release 版可以省去此兩句
#define ngx_queue_remove(x) \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
(x)->prev = NULL; \
(x)->next = NULL
#else
// 刪除一個節點
#define ngx_queue_remove(x) \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next
#endif
//
// split 作用如下圖所示:
//
// ________________________________________________
// ||--------------------------------------------||
// || ||
// |---| => |---| => … => |---| => |---| => … => |---| |---|
// | h | | | | q | | | | | | n |
// |---| <= |---| <= … <= |---| <= |---| <= … <= |---| |---|
//
// __________________________ __________________________________
// ||----------------------|| ||------------------------------||
// || || || ||
// |---| => |---| => … => |---| |---| => |---| => … => |---| => |---|
// | h | | | | | | q | | | | | | n |
// |---| <= |---| <= … => |---| |---| <= |---| <= … <= |---| <= |---|
//
#define ngx_queue_split(h, q, n) \
(n)->prev = (h)->prev; \
(n)->prev->next = n; \
(n)->next = q; \
(h)->prev = (q)->prev; \
(h)->prev->next = h; \
(q)->prev = n;
// 將 n 代表的佇列(n 為佇列頭)接到 h 表示的佇列後面
//
// _________________________ _________________________
// ||---------------------|| ||---------------------||
// || || || ||
// |---| => |---| => … => |---| |---| => |---| => … => |---|
// | h | | | | | | n | |n1 | | |
// |---| <= |---| <= … <= |---| |---| <= |---| <= … <= |---|
//
// ________________________________________________________
// ||----------------------------------------------------||
// || ||
// |---| => |---| => … => |---| =========> |---| => … => |---|
// | h | | | | | |n1 | | |
// |---| <= |---| <= … <= |---| <========= |---| <= … <= |---|
//
#define ngx_queue_add(h, n) \
(h)->prev->next = (n)->next; \
(n)->next->prev = (h)->prev; \
(h)->prev = (n)->prev; \
(h)->prev->next = h;
// 一般type如下:
// typedef struct {
// …
// LINK q
// } TYPE
// 所以這個巨集可以通過 q 找到其所在的結構體 TYPE 變數的地址
#define ngx_queue_data(q, type, link) \
(type *) ((u_char *) q - offsetof(type, link))
ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
void ngx_queue_sort(ngx_queue_t *queue,
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
#endif /* _NGX_QUEUE_H_INCLUDED_ */
佇列原始檔ngx_queue.c
#include <ngx_config h=""><span class="preprocessor" style="color: rgb(136, 0, 0); ">#include </span><ngx_core h=""><span class="comment" style="color: rgb(136, 136, 136); ">/*
* find the middle queue element if the queue has odd number of elements
* or the first element of the queue's second part otherwise
*/</span>
<span class="comment" style="color: rgb(136, 136, 136); ">//</span>
<span class="comment" style="color: rgb(136, 136, 136); ">// 這是用兩個指標來找連結串列中點的典型應用,在很多技巧性問答中常出現。</span>
<span class="comment" style="color: rgb(136, 136, 136); ">//</span>
ngx_queue_t *
ngx_queue_middle(ngx_queue_t *<span class="built_in" style="font-weight: bold; ">queue</span>)
{
ngx_queue_t *middle, *next;
<span class="comment" style="color: rgb(136, 136, 136); ">// middle 從第一個節點開始</span>
middle = ngx_queue_head(<span class="built_in" style="font-weight: bold; ">queue</span>);
<span class="comment" style="color: rgb(136, 136, 136); ">// 如果佇列只有一個節點,或者為空</span>
<span class="keyword" style="font-weight: bold; ">if</span> (middle == ngx_queue_last(<span class="built_in" style="font-weight: bold; ">queue</span>)) {
<span class="keyword" style="font-weight: bold; ">return</span> middle;
}
<span class="comment" style="color: rgb(136, 136, 136); ">// next 也從第一個節點開始</span>
next = ngx_queue_head(<span class="built_in" style="font-weight: bold; ">queue</span>);
<span class="keyword" style="font-weight: bold; ">for</span> ( ;; ) {
middle = ngx_queue_next(middle);
next = ngx_queue_next(next);
<span class="comment" style="color: rgb(136, 136, 136); ">// 偶數個的情況是在這裡返回</span>
<span class="keyword" style="font-weight: bold; ">if</span> (next == ngx_queue_last(<span class="built_in" style="font-weight: bold; ">queue</span>)) {
<span class="keyword" style="font-weight: bold; ">return</span> middle;
}
next = ngx_queue_next(next);
<span class="comment" style="color: rgb(136, 136, 136); ">// 奇數個是在這裡返回</span>
<span class="keyword" style="font-weight: bold; ">if</span> (next == ngx_queue_last(<span class="built_in" style="font-weight: bold; ">queue</span>)) {
<span class="keyword" style="font-weight: bold; ">return</span> middle;
}
}
}
<span class="comment" style="color: rgb(136, 136, 136); ">/* the stable insertion sort */</span>
<span class="comment" style="color: rgb(136, 136, 136); ">//</span>
<span class="comment" style="color: rgb(136, 136, 136); ">// 這是一個穩定就地排序(Stable In-place Sorting)。演算法的三個效能指標(時間複雜度,空間複雜度,穩定性)</span>
<span class="comment" style="color: rgb(136, 136, 136); ">// 相比之下,quick sort 和 merge sort 更快。但 quick sort 是非穩定的,merge sort 使用 O(n) 額外空間</span>
<span class="comment" style="color: rgb(136, 136, 136); ">//</span>
<span class="keyword" style="font-weight: bold; ">void</span>
ngx_queue_sort(ngx_queue_t *<span class="built_in" style="font-weight: bold; ">queue</span>,
ngx_int_t (*cmp)(<span class="keyword" style="font-weight: bold; ">const</span> ngx_queue_t *, <span class="keyword" style="font-weight: bold; ">const</span> ngx_queue_t *))
{
ngx_queue_t *q, *prev, *next;
q = ngx_queue_head(<span class="built_in" style="font-weight: bold; ">queue</span>);
<span class="comment" style="color: rgb(136, 136, 136); ">// 空佇列</span>
<span class="keyword" style="font-weight: bold; ">if</span> (q == ngx_queue_last(<span class="built_in" style="font-weight: bold; ">queue</span>)) {
<span class="keyword" style="font-weight: bold; ">return</span>;
}
<span class="keyword" style="font-weight: bold; ">for</span> (q = ngx_queue_next(q); q != ngx_queue_sentinel(<span class="built_in" style="font-weight: bold; ">queue</span>); q = next) {
prev = ngx_queue_prev(q);
next = ngx_queue_next(q);
ngx_queue_remove(q);
<span class="comment" style="color: rgb(136, 136, 136); ">// 在已排好序的節點中,向前找比 q 的內容小的。比較的標準由 cmp 確定</span>
<span class="keyword" style="font-weight: bold; ">do</span> {
<span class="keyword" style="font-weight: bold; ">if</span> (cmp(prev, q) <= <span class="number" style="color: rgb(0, 136, 0); ">0</span>) {
<span class="keyword" style="font-weight: bold; ">break</span>;
}
prev = ngx_queue_prev(prev);
} <span class="keyword" style="font-weight: bold; ">while</span> (prev != ngx_queue_sentinel(<span class="built_in" style="font-weight: bold; ">queue</span>));
<span class="comment" style="color: rgb(136, 136, 136); ">// 找到 prev 是比 q 的內容小的,在 prev 後面插入</span>
ngx_queue_insert_after(prev, q);
}
}
</ngx_core></ngx_config>
從上面可以看出,create 是從 pool 分配定義 list 結構的記憶體,分配表頭節點的記憶體。init 是初始化已有的 list。
Reference
-
轉載請註明來自柳大Poechant(鍾超Michael)的CSDN部落格:
鍾超Michael的部落格:Blog.CSDN.net/Poechant
鍾超Michael的微博:鍾超Michael的新浪微博
-
相關文章
- Nginx原始碼完全註釋(6)core/murmurhashNginx原始碼
- Nginx原始碼完全註釋(8)ngx_errno.cNginx原始碼
- Nginx原始碼完全註釋(9)nginx.c: ngx_get_optionsNginx原始碼
- Nginx原始碼完全註釋(5)core/ngx_cpuinfo.cNginx原始碼UI
- 原始碼完全註釋:socket select原始碼
- Nginx原始碼完全註釋(1)ngx_alloc.h / ngx_alloc.cNginx原始碼
- Nginx原始碼完全註釋(7)ngx_palloc.h/ngx_palloc.cNginx原始碼
- Nginx原始碼完全註釋(3)ngx_list.h / ngx_list.cNginx原始碼
- Nginx原始碼完全註釋(2)ngx_array.h / ngx_array.cNginx原始碼
- Nginx 原始碼完全剖析(11)ngx_spinlockNginx原始碼
- Nginx 原始碼完全剖析(10)ngx_radix_treeNginx原始碼
- 《Linux核心完全註釋》學習筆記:2.7 Linux核心原始碼的目錄結構Linux筆記原始碼
- HashMap原始碼(JDK1.8)-手動註釋HashMap原始碼JDK
- Bootstrap的Model原始碼詳細註釋 (轉)boot原始碼
- Nginx篇--Nginx原始碼搭建Nginx原始碼
- EventBus原始碼解讀詳細註釋(4)register時重新整理的兩個map原始碼
- Redux原始碼完全解讀Redux原始碼
- bootstrap-modal.js學習筆記(原始碼註釋)bootJS筆記原始碼
- Dubbo原始碼解析之服務釋出與註冊原始碼
- 從Python原始碼註釋,自動生成API文件Python原始碼API
- 使用ehcache元註釋提高Spring 效能原始碼案例Spring原始碼
- C231n-KNN-assignment1-完全程式碼及註釋KNN
- C231n-SVM-assignment1-完全程式碼及註釋
- nginx原始碼安裝Nginx原始碼
- NGINX原始碼閱讀Nginx原始碼
- Nginx 原始碼安裝Nginx原始碼
- 原始碼安裝Nginx原始碼Nginx
- Nginx的nginx.conf配置檔案中文註釋說明Nginx
- CSS程式碼註釋CSS
- php程式碼註釋PHP
- maven下載原始碼,解決中文註釋為亂碼的問題Maven原始碼
- DialogFragment使用到原始碼完全解析Fragment原始碼
- docker原始碼安裝NginxDocker原始碼Nginx
- macbook 原始碼安裝 nginxMac原始碼Nginx
- Centos原始碼安裝NginxCentOS原始碼Nginx
- ArcGIS VBA - VBA+AO入門15例完全註釋版
- snownlp類庫(中文情感分析)原始碼註釋及使用原始碼
- NumPyCookbook帶註釋原始碼四、連線NumPy與剩餘世界原始碼