美文网首页nginx
nginx源码分析-双向链表

nginx源码分析-双向链表

作者: besmallw | 来源:发表于2020-08-24 15:21 被阅读0次

基本介绍

nginx的双向链表结构里只有与节点关联的信息,没有任何与业务相关的信息,从而做到数据与业务解耦

数据结构定义

// 双向链表
typedef struct ngx_queue_s  ngx_queue_t;

struct ngx_queue_s {
    ngx_queue_t  *prev; // 前一个节点
    ngx_queue_t  *next; // 后一个节点
};

使用方法

在具体的业务的数据结构中,挂载一个ngx_queue_t结构

  • 怎样才能获取到具体的ngx_queue_t节点呢?
    使用一个宏定义的方法,可以通过结构体中的成员找到结构体的首地址
#define ngx_queue_data(q, type, link)                                         \
    (type *) ((u_char *) q - offsetof(type, link))

上面的方法类似于linux内核中大量使用的一个宏定义

#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) - (size_t)(&((type *)0)->member)))

这个宏可以分为5步(减号后面):

  1. 0
  2. ((type) *0)
  3. ((type *)0)->member)
  4. &((type *)0)->member
  5. (size_t)(&((type *)0)->member)
  1. 内存地址0开始
  2. 将0转换为type类型的结构体指针,让编译器认为这个结构是开始于程序段的起始位置
  3. 引用结构体的member成员
  4. 取这个成员的地址(不关心具体内容)
  5. 将取到的地址强制转换为size_t类型

最终得到的是结构体成员相对于结构体首地址的偏移

减号前面:
ptr是具体的结构体成员,用ptr的地址减掉上面说的偏移,就得到结构体的首地址了

函数实现

// 初始化链表
#define ngx_queue_init(q)                                                     \
    (q)->prev = q;                                                            \
    (q)->next = q

// 判断是否为空
#define ngx_queue_empty(h)                                                    \
    (h == (h)->prev)

// x插在h的位置
#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

// 插在h后
#define ngx_queue_insert_tail(h, x)                                           \
    (x)->prev = (h)->prev;                                                    \
    (x)->prev->next = x;                                                      \
    (x)->next = h;                                                            \
    (h)->prev = x

// h是尾部  返回链表的第一个元素
#define ngx_queue_head(h)                                                     \
    (h)->next

// h是头部  返回连表的最后一个元素
#define ngx_queue_last(h)                                                     \
    (h)->prev


#define ngx_queue_sentinel(h)                                                 \
    (h)


#define ngx_queue_next(q)                                                     \
    (q)->next


#define ngx_queue_prev(q)                                                     \
    (q)->prev


#if (NGX_DEBUG)
// 移除
#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

// 分割链表
#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;


#define ngx_queue_add(h, n)                                                   \
    (h)->prev->next = (n)->next;                                              \
    (n)->next->prev = (h)->prev;                                              \
    (h)->prev = (n)->prev;                                                    \
    (h)->prev->next = h;

2020.8.24 15:21 深圳

相关文章

  • nginx源码分析-双向链表

    基本介绍 nginx的双向链表结构里只有与节点关联的信息,没有任何与业务相关的信息,从而做到数据与业务解耦 数据结...

  • java.util.LinkedList(JDK1.8)源代码浅

    定义 LinkedList是一个双向链表类型的集合。 所谓双向链表就是链表上的元素都有上一个,下一个 源码分析 通...

  • LinkedList源码初探

    准备: LinkedList是基于链表(双向循环链表)结构的一种List,在分析LinkedList源码之前我们先...

  • 五、双向链表

    双向链表 此前介绍的链表,也叫做单向链表使用双向链表可以提升链表的综合性能 修改之前的单链表的源码: 双向链表 –...

  • 五. java数据结构 - 双向链表

    1. 双向链表的操作分析和实现 使用带 head 头的双向链表实现 –水浒英雄排行榜 分析 双向链表的遍历,添加,...

  • nginx 双向链表

    ngx_queue_t双向链表是Nginx提供的轻量级链表容器,它与Nginx的内存池无关,因此,这个链表将不会负...

  • 数据结构——双向链表、循环链表

    源码地址请点击此处 本文介绍链表的两个衍生结构:双向链表和循环链表。 双向链表 前面介绍的单向链表中,每个节点的地...

  • LinkedList源码解析

    LinkedList 是有序并且可以元素重复的集合,底层是基于双向链表的。 源码分析 构造方法 Node add方...

  • 总结

    Android篇 数据结构与算法顺序表 - ArrayList源码链表 - 单向链表、双向链表 - LinkedL...

  • 数据结构之双向链表

    1.双向链表 1.1双向链表创建示意图 分析 双向链表的遍历,添加,修改,删除的操作思路===》代码实现: 遍历 ...

网友评论

    本文标题:nginx源码分析-双向链表

    本文链接:https://www.haomeiwen.com/subject/andnjktx.html