浅谈Linux Kernel 中循环链表的实现

  前阵子在弄缓存的时候,我们需要将qemu对于磁盘镜像文件写请求串成一个链表,最终将这个链表里面的写请求全部刷回到镜像文件里面,那么我们便需要一个强健,可靠的链表的接口,于是我们仿照Linux 2.4.0的内核,来造了这么一个链表的轮子。今天抽抽空来记录一下。

  链表,估计学过数据结构这门课程的人都对其印象深刻,因为老师们都喜欢将它放在比较靠前的地方讲,很多人都认为链表是一种非常easy的数据结构。因为链表的逻辑非常地简单,每个节点就是分成指针和数据,一头一尾地通过指针将每个节点串起来,没有树形(二叉树,B-树,红黑树,基树等)的数据结构那样复杂的前驱和后继的结构,以及复杂的结构伸展变化的操作。并且链表的各种操作的复杂度也都非常容易估算出来。

  可是,要实现一个非常可靠,通用,强健的链表数据结构却是很有难度的。

  一般地,我们都会对一个循环链表的节点做出如下的定义:

 struct node {
     int val;
     struct node *prev;
     struct node *next;
 };

  代码很简单,构造完一个链表之后会有如下的效果:

  这只是普通链表的实现,当我们需要创建另一种数据结构组成的链表的时候,如果还是按照上述的方法来创建一个链表,那么我们就不得不重新定义一个链表的节点

来存储这种数据结构,如果某个应用里面有一万种数据结构,那我们岂不要定义一万种链表的数据结构,及其查询,删除,修改的应用接口?

  我们可以尝试着将链表单独地抽离出来,对其进行解耦,这样我们便可以将他当作一套通用的应用接口来使用了。

  先来定义一下链表节点的访问入口:

typedef struct cir_list_head {
    struct cir_list_head *prev, *next;
}gc_list;

  现在我们为特定的存储数据来定义一个链表的节点:

typedef struct test_list{
    gc_list list;
    int val;
} test_list;

注意,我们在这里就将链表节点的访问接口打包插入到了链表节点里面,仔细体会,我们最终所构建的效果如下:

接下来我们来看看如何通过gc_list * 指针来访问这些节点里面的数据:

我们希望能够通过结构体test_list里面的list(gc_list)来获取数据val,也就是说在同一个结构体下,通过其中一个结构体成员来获取另一个结构体成员的信息,

这个时候,我们就需要用到一些奇技淫巧:

#define OFFSETOF(type, member)        (size_t)&(((type *)0)->member)

#define container_of(ptr, type, member) ({                              const typeof( ((type *)0)->member ) *__mptr = (ptr);            (type *)( (char *)__mptr - OFFSETOF(type,member) );})

盗用一幅图描述上面的这几行代码的意思,不用太多的文字的解释~~,通过上面的这个接口我们便可以随意地操控循环链表里面的各种数据啦~,这种封装方法

比较好的地方便是你再也不用为每一种链表里面的数据特意去重写一套API,注意这段代码和编译器平台相关(主要都在GCC平台下),并不具备100%的可移植性。

相关链接:

  造的一个循环链表的轮子:https://github.com/jusonalien/VM-DB/blob/master/list.h

  测试使用代码:https://github.com/jusonalien/VM-DB/blob/master/TestList.c

  关于container_of宏的详尽的解释: http://radek.io/2012/11/10/magical-container_of-macro/

时间: 2024-08-27 19:46:11

浅谈Linux Kernel 中循环链表的实现的相关文章

浅谈Linux系统中的7种运行级别及其原理

浅谈Linux系统中的7种运行级别 Linux系统7个运行级别(runlevel): 运行级别0: 系统停机状态,系统默认运行级别不能设为0,否则不能正常启动. 运行级别1: 单用户工作状态,root权限,用于系统维护,禁止远程登陆. 运行级别2: 多用户状态(没有NFS). 运行级别3: 完全的多用户状态(有NFS),登陆后进入控制台命令行模式. 运行级别4: 系统未使用,保留. 运行级别5: X11控制台,登陆后进入图形GUI模式. 运行级别6: 系统正常关闭并重启,默认运行级别不能设为6,

浅谈Linux 内存中的Cache: buffers 与 cached

Linux 内存中的Cache,真的能被回收么? 您真的了解Linux的free命令么? 在Linux系统中,我们经常用free命令来查看系统内存的使用状态.在一个RHEL6的系统上,free命令的显示内容大概是这样一个状态: 这里的默认显示单位是kb,我的服务器是128G内存,所以数字显得比较大.这个命令几乎是每一个使用过Linux的人必会的命令,但越是这样的命令,似乎真正明白的人越少(我是说比例越少). 一般情况下,对此命令输出的理解可以分这几个层次: 不了解.这样的人的第一反应是:天啊,内

浅谈Linux系统中如何查看进程 ——ps,pstree,top,w,全解

进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:ps命令主要用于查看系统中进程的状态. 用法:ps [选项] 主要选项如下: -e 显示所有进程 -a 跟终端无关的进程 (BSD风格,不加横杆) -x 跟终端有关的进程 -u 发起者 -F 额外信息 -f 显示完整信息 -j 以作业的方式显示进程 -H 显示进程的关系 -o 自定义显示哪些字段 单一

浅谈Linux中的信号机制(二)

首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Linux内核源码评头论足.以后的路还很长,我还是一步一个脚印的慢慢走着吧,Linux内核这座山,我才刚刚抵达山脚下. 好了,言归正传,我接着昨天写下去.如有错误还请各位看官指正,先此谢过. 上篇末尾,我们看到了这样的现象:send进程总共发送了500次SIGINT信号给rcv进程,但是实际过程中rcv只接受/处理了1

浅谈linux中shell变量$#,[email&#160;protected],$0,$1,$2,$?的含义解释

浅谈linux中shell变量$#,[email protected],$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,[email protected],$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 摘抄自:ABS_GUIDE 下载地址:http://www.tldp.org/LDP/abs/abs-guide.pdf linux中shell变量$#,[email protected],$

Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO https://blog.csdn.net/column/details/21963.html 部分代码会放在我的的Github:https://github.com/h2pl/ 浅谈 Linux

浅谈linux内核栈(基于3.16-rc4)

在3.16-rc4内核源码中,内核给每个进程分配的内核栈大小为8KB.这个内核栈被称为异常栈,在进程的内核空间运行时或者执行异常处理程序时,使用的都是异常栈,看下异常栈的代码(include/linux/sched.h): 1 union thread_union { 2 struct thread_info thread_info; 3 unsigned long stack[THREAD_SIZE/sizeof(long)]; 4 }; THREAD_SIZE值为8KB,因此内核为进程的异常

(转)浅谈 Linux 内核无线子系统

前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高层次的问题. 跟踪探索了一段时间的源代码后,我写下了这篇总结,希望在 Linux 无线网络的工作原理上,读者能从这篇文章获得一个具有帮助性的概览. 1.全局概览 在开始探索 Linux 无线具体细节之前,让我们先来把握一下 Linux 无线子系统整体结构.如图1,展示了 Linux 无线子系统各个模

浅谈Linux下Makefile编写

浅谈Linux下Makefile的编写 前言:本文简要介绍Makefile文件的编写规范,结合具体项目中的应用进行讲解. 具体代码地址: https://github.com/AnSwErYWJ/DogFood/blob/master/Makefile 简介 Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作.而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关