队列头文件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. Nomad 了解

    Introduction to Nomad Welcome to the intro guide to Nomad! This guide is the best place to start wit ...

  2. Sql Server 2012 存储过程的调试

    [一]Sql Server 关于存储过程调试SQL2000是在查询分析器中的对象浏览器中选中需要调试的存储过程,右键----调试---输入参数开始调试.sqlserver2008中则完全不同,变成了必 ...

  3. RK3288 通过指令查看当前显示内容(framebuffer)

    $ adb shell root@xxx:/ # cd /dev/graphics cd /dev/graphics root@xxx:/dev/graphics # ls ls fb0 fb1 fb ...

  4. C/S模式与B/

    网络程序开发的两种计算模式--C/S模式与B/S模式.两种各有千秋,用于不同场合. C/S适用于专人使用,安全性要求较高的系统: B/S适用于交互性比较频繁的场合,容易被人们所接受,倍受用户和软件开发 ...

  5. xsd解析

    1. 解释: <xsd:element name="interceptors"> <xsd:annotation> 这一块是对第一行的注解(解释) < ...

  6. Java基础--NIO

    NIO库在JDK1.4中引入,它以标准Java代码提供了高速的,面向块的IO,弥补了之前同步IO的不足. 缓冲区Buffer Buffers是一个对象,包含了一些要写入或读出的数据.在面向流的IO模型 ...

  7. 20165226 2017-2018-2《Java程序设计》课程总结

    目录 一.作业汇总 二.总结 三.问卷调查 一.作业汇总 预备作业1:我期望的师生关系 预备作业2:学习基础和C语言基础调查 预备作业3:linux安装及学习 第一周: Java入门 第一周学习总结 ...

  8. python(ValueError: invalid literal for int() with base 10: 'abc' ‘1.0‘’’)强制类型转换

    int()函数只能转化数字组成的字符串,看例子: >>> a=' >>> int(a) 123 >>> b='abc' >>> ...

  9. 使用wifi网卡笔记2----概念及工具iw(STA模式)

    1.认证和加密的概念 (1)概念 (2)阶段划分 初级版本:认证不需要密码, 传输不需要加密 认证不需要密码, 传输需要加密(用WEP算法) 认证需要密码(用WEP算法), 传输需要加密(用WEP算法 ...

  10. Collection集合学习(二)———List接口与具体实现

    二.List接口: 一个可以包含重复元素的Collection,List中的元素不会自动排序,元素顺序由添加时的顺序决定. 具体实现类包括Vector(线程安全的),ArrayList,LinkedL ...