tail queue代码阅读
tail queue是bdb中用的最多的数据结构. 定义在 src/dbinc/queue.h:
注: TRACEBUF,QMD_TRACE_HEAD等是为了 queue代码的debug, 这里移除出去. 数据结构
======== ```
// type 即为 用户定义的 类型. 比如 db.h,
// struct __db_txn {
// * TAILQ_HEAD(__kids, __db_txn) kids;
// */
// struct __kids { type 即为 _db_txn. 问题: 用什么不直接用 TAILQ_HEAD(__kids, __db_txn) kids?
// struct __db_txn *tqh_first;
// struct __db_txn **tqh_last;
// } kids; #define TAILQ_HEAD(name, type) \ // 理解为 "头结点"
struct name { \
struct type *tqh_first; /* first element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqh_last; /* addr of last next element */ \ // "最后一个元素的tqe_next" 的地址
} #define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqe_prev; /* address of previous next element */ \ "前一个元素的tqe_next" 的地址
}
``` 方法定义
========= ```
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first) /**
* 这里做了一个trick. 看TAILQ_HEAD 和TAILQ_ENTRY的定义, 只有 TAILQ_HEAD给了struct name.
* 所以 强制转为 `(struct headname *)`, (而不是 `(struct entryname *)`). 但是 TAILQ_HEAD 和
* TAILQ_ENTRY 的定义是相同的, `(head)->tqh_last)` 为 最后一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 此 `struct entryname` 的地址.
* `(((struct headname *)((head)->tqh_last))->tqh_last)` 即为:
* `(((struct entryname *)((head)->tqh_last))->tqe_prev)`. 倒数第二个元素的 tqe_next.
* TAILQ_PREV 的定义也是这么理解.
*/
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) /**
* field 为type中, queue entry的field. 其 `(elm)->field.tqe_prev)` 为 前一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 前一个元素的 queue entry field 的地址.
* `(((struct headname *)((elm)->field.tqe_prev))->tqh_last)` 即为:
* `(((struct entryname *)((elm)->field.tqe_prev))->tqe_prev)`. 前第二个元素的 tqe_next.
*/
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field)) #define TAILQ_INIT(head) do {
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \ // tqh_last 为 头结点本身的 tqh_first指针的地址
} while () #define TAILQ_CONCAT(head1, head2, field) do { \ // 合并两个queue
if (!TAILQ_EMPTY(head2)) { \ // 若q2 不为空
*(head1)->tqh_last = (head2)->tqh_first;\ // 调整 q1 末尾节点的 tqe_next
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ // 调整q2 第一个节点的tqe_prev
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \ // 重置q2的头结点
} \
} while () #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ // 将elm 插到 listelm 后面
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ // elm->next=listelm->next
TAILQ_NEXT((elm), field)->field.tqe_prev = \ // 若listelm不为队尾, 调整elm->next->pre
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // listelm为队尾, 调整tqh_last
TAILQ_NEXT((listelm), field) = (elm); \ // 调整listelm->next
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ // 调整elm->pre
} while () #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \ // 若listelm为第一个元素, 则tqe_prev为 tqh_first \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // queue为空的情况
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ // 第一个元素的 tqe_prev 指向头结点的tqh_first
} while () #define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \ // 若queue为空, tqh_last 指向 tqh_first
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \ // elm 不为队尾, 调整elm->next->pre
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \ // elm 为队尾, 调整tqh_last
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ // 若 elm为队首, 其tqe_prev为 tqh_first
} while ()
```
tail queue代码阅读的更多相关文章
- 代码阅读分析工具Understand 2.0试用
Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...
- Android 上的代码阅读器 CoderBrowserHD 修改支持 go 语言代码
我在Android上的代码阅读器用的是 https://github.com/zerob13/CoderBrowserHD 改造的版本,改造后的版本我放在 https://github.com/ghj ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- [置顶] Linux协议栈代码阅读笔记(一)
Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...
- 图形化代码阅读工具——Scitools Understand
Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java, ...
- Python - 关于代码阅读的一些建议
初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...
- MediaInfo代码阅读
MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...
- Tools - 一些代码阅读的方法
1 初始能力 让阅读思路清晰连贯,保持在程序的流程架构和逻辑实现上,不被语法.编程技巧和业务流程等频繁地阻碍和打断. 语言基础:熟悉基础语法,常用的函数.库.编程技巧等: 了解设计模式.构建工具.代码 ...
- Bleve代码阅读(二)——Index Mapping
引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...
随机推荐
- 浅析jquery ui的datepicker组件
今天计划在博客上添加一个日历,方便用户查看日期.Google了一圈,最终决定使用jquery ui的datepicker部件实现.原因有三:Datepicker使用配置比较简洁,几行代码就可以得到一个 ...
- 汉化PLSQL怎么改变字体的大小及关键字颜色
打开工具---首选项-----编辑器---语法高亮进行设置自己喜欢的颜色---应用--确定 英文版PLSQL:tools----preferences---userinterface项目下的edite ...
- Magento1.9批量修改产品 Attribute Set
今天修改产品时遇到这样一个需求:重新设置产品的 Attribute Set,使用的是Magento1.9系统,Magento提供这样一个插件 Flagbit Change Attribute Set: ...
- Linux入门学习,开启端口号
之前买了一个阿里云Centos 7服务器,默认开启22端口和80端口,想开启其他端口号如何做 1.开启端口号 [root@localhost ~]# /sbin/iptables -I INPUT - ...
- 一个div,包含两个div,调整文字位置和div平均分布
网页中经常会用到,一个div下平均分布两个小的div,两个小的div,显示的内容为图片还比较好处理,显示文字则不好控制效果,今天写了一个如图效果的 html: <div class=" ...
- markdown基本操作
# 一级标题 ## 二级标题,以此类推 - 或者 * ...
- Java(多态)动手动脑
1> 请看以下"变态"的类(参看示例ParentChildTest.java) 上述代码的特点是: 子类和父类定义了一模一样的字段和方法 运行以下测试代码 1. 上边的程序运 ...
- CentOS 6.5 RPM包方式安装 Mysql 5.6
1. 下载MySQL 5.6 下载页面:http://dev.mysql.com/downloads/mysql/此处选择“Red Hat Enterprise Linux 6 / Oracle Li ...
- 最全的Resharper快捷键汇总
编辑Ctrl + Space 代码完成 Ctrl + Shift + Space代码完成Ctrl + Alt + Space代码完成Ctrl + P 显示参数信息Alt + Insert 生成构造函数 ...
- flask-admin章节四:flask session的使用
1. 关于session flask session可能很多人根本都没有使用过,倒是cookie大家可能使用得比较多.flask cookie使用起来比较简单,就两个函数,读取和设置. 具体使用方式如 ...