队列头文件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
#include /*
* find the middle queue element if the queue has odd number of elements
* or the first element of the queue's second part otherwise
*/ //
// 这是用两个指针来找链表中点的典型应用,在很多技巧性问答中常出现。
//
ngx_queue_t *
ngx_queue_middle(ngx_queue_t *queue)
{
ngx_queue_t *middle, *next; // middle 从第一个节点开始
middle = ngx_queue_head(queue); // 如果队列只有一个节点,或者为空
if (middle == ngx_queue_last(queue)) {
return middle;
} // next 也从第一个节点开始
next = ngx_queue_head(queue); for ( ;; ) {
middle = ngx_queue_next(middle); next = ngx_queue_next(next); // 偶数个的情况是在这里返回
if (next == ngx_queue_last(queue)) {
return middle;
} next = ngx_queue_next(next); // 奇数个是在这里返回
if (next == ngx_queue_last(queue)) {
return middle;
}
}
} /* the stable insertion sort */
//
// 这是一个稳定就地排序(Stable In-place Sorting)。算法的三个性能指标(时间复杂度,空间复杂度,稳定性)
// 相比之下,quick sort 和 merge sort 更快。但 quick sort 是非稳定的,merge sort 使用 O(n) 额外空间
//
void
ngx_queue_sort(ngx_queue_t *queue,
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
{
ngx_queue_t *q, *prev, *next; q = ngx_queue_head(queue); // 空队列
if (q == ngx_queue_last(queue)) {
return;
} for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) { prev = ngx_queue_prev(q);
next = ngx_queue_next(q); ngx_queue_remove(q); // 在已排好序的节点中,向前找比 q 的内容小的。比较的标准由 cmp 确定
do {
if (cmp(prev, q) <= 0) {
break;
} prev = ngx_queue_prev(prev); } while (prev != ngx_queue_sentinel(queue)); // 找到 prev 是比 q 的内容小的,在 prev 后面插入
ngx_queue_insert_after(prev, q);
}
}

从上面可以看出,create 是从 pool 分配定义 list 结构的内存,分配表头节点的内存。init 是初始化已有的 list。

Nginx源码完全注释(4)ngx_queue.h / ngx_queue.c的更多相关文章

  1. Nginx源码完全注释(6)core/murmurhash

    下面是摘自 Google Code 的 Murmurhash 开源项目主页上的 Murmurhash2,Nginx 就是采用的这个. uint32_t MurmurHash2 ( const void ...

  2. Nginx 源码完全注释(11)ngx_spinlock

    Nginx 是多进程模式的,一个 master 与多个 workers,一般工作在多核 CPU 上,所以自旋锁就是必须用到的.Nginx 中的自旋锁的定义,位于 ngx_spinlock.c 中,如下 ...

  3. Nginx源码完全注释(2)ngx_array.h / ngx_array.c

    数组头文件 ngx_array.h #include <ngx_config.h> #include <ngx_core.h> struct ngx_array_s { voi ...

  4. nginx源码完全注释(1)ngx_alloc.h / ngx_alloc.c

    首先看 ngx_alloc.h 文件,主要声明或宏定义了 ngx_alloc,ngx_calloc,ngx_memalign,ngx_free. /* * Copyright (C) Igor Sys ...

  5. Nginx源码完全注释(7)ngx_palloc.h/ngx_palloc.c

    ngx_palloc.h /* * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86. * On Windo ...

  6. Nginx源码完全注释(3)ngx_list.h / ngx_list.c

    列表头文件ngx_list.h #ifndef _NGX_LIST_H_INCLUDED_ #define _NGX_LIST_H_INCLUDED_ #include <ngx_config. ...

  7. Nginx 源码完全注释(10)ngx_radix_tree

    ngx_radix_tree.h // 未被使用的节点 #define NGX_RADIX_NO_VALUE (uintptr_t) -1 typedef struct ngx_radix_node_ ...

  8. Nginx源码完全注释(9)nginx.c: ngx_get_options

    本文分析 ngxin.c 中的 ngx_get_options 函数,其影响: nginx.c 中的: static ngx_uint_t ngx_show_help; static ngx_uint ...

  9. Nginx源码完全注释(8)ngx_errno.c

    errno.h中的strerror(int errno)可以确定指定的errno的错误的提示信息.在 Nginx 中,将所有错误提示信息预先存储在一个数组里,而预先确定这个数组的大小,是在自动化脚本中 ...

随机推荐

  1. 模仿36。杀毒~button(转)

    <Style x:Key="360btn" TargetType="{x:Type Button}"> <Setter Property=&q ...

  2. 转发 GSLB概要和实现原理

    What is GSLB Global Server Load Balancing 中文:全局负载均衡 SLB(Server load balancing)是对集群内物理主机的负载均衡,而GSLB是对 ...

  3. drill 试用

    1. 下载 http://drill.apache.org/ 2. 启动本地模式 bin/sqlline -u jdbc:drill:zk=local 3. 查询数据 select c.r_name ...

  4. LuaJavaBridge

    http://www.360doc.com/content/14/0117/13/9200790_345940368.shtml quick目录结构介绍 http://cn.cocos2d-x.org ...

  5. 软件设计----LisKov替换原则(LSP)

    LisKov替换原则的定义:一个软件实体如果使用的是一个基类的话,一定适用于其子类,而且根本不能觉察出基类对象和子类对象的区别. 1)怎么理解上面的概念?就是我们程序设计的子类型能够完全替换父类型,而 ...

  6. SQLServer中求两个字符串的交集(字符串以符号分隔)

    两个字符串,以特定符号分隔(例如‘,’号),求交集 第一种情况: declare @m varchar(100),@n varchar(100)select @m=',2,3,5,7,8,9,10,' ...

  7. CFile用法(转)

    一.各种关于文件的操作在程序设计中是十分常见,如果能对其各种操作都了如指掌,就可以根据实际情况找到最佳的解决方案,从而在较短的时间内编写出高效的代码,因而熟练的掌握文件操作是十分重要的.本文将对Vis ...

  8. C++中const使用注意要点(二)

    当const修饰类的成员变量 1.const修饰类的非静态成员时必须在构造函数初始化列表上初始化: 在构造函数内会提示表达式必须是可修改的左值,因为在构造函数内并不是初始化,仅仅是赋值,而const类 ...

  9. nginx和php-fpm通信的两种方式 unix socket和TCP

    nginx和fastcgi的通信方式有两种,一种是TCP 一种是unix socket TCP使用的是 127.0.0.1:9000端口,将fastcgi_pass参数修改为127.0.0.1:900 ...

  10. java Annotation的应用

    一.Annotation 示例 Override Annotation @Override public void onCreate(Bundle savedInstanceState); 二.Ann ...