浅谈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 *))->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/
浅谈Linux Kernel 中循环链表的实现的更多相关文章
- (转)浅谈 Linux 系统中的 SNMP Trap
原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...
- 浅谈Linux系统中如何查看进程
进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:p ...
- 浅谈Linux系统中如何查看进程 ——ps,pstree,top,w,全解
进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:p ...
- 浅谈linux系统中pdf文件的默认打开方式
atril.gimp和evince,三者均可以打开application/pdf格式文件.gimp为一款图像处理软件:atril为mate环境下常用的文档查看器:evince为gnome环境下常用的文 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...
- 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释
浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...
- 浅谈 Linux 内核无线子系统
浅谈 Linux 内核无线子系统 本文目录 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 L ...
- (转)浅谈 Linux 内核无线子系统
前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高 ...
随机推荐
- 大数据学习——mapreduce汇总手机号上行流量下行流量总流量
时间戳 手机号 MAC地址 ip 域名 上行流量包个数 下行 上行流量 下行流量 http状态码 1363157995052 13826544101 5C-0E-8B-C7-F1-E0:CMCC 12 ...
- mysql异常Incorrect string value: '\xE6\xB5\x8B\xE8\xAF\x95' for column 'region_name'
Incorrect string value: '\xE6\xB5\x8B\xE8\xAF\x95' for column 'region_name' insert语句加的该字段有汉字,乱码造成的 解 ...
- python022 Python3 面向对象
Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触 ...
- python中的“坑”—持续更新
1.判断是否是回文 def is_back(s): ]==(s if s.strip() else False) print(is_back('上海自来水来自海上')) print(is_back(' ...
- poj3468区间延迟更新模板题
#include<stdio.h> #include<string.h> #define N 100000 struct st{ int x,y; __int64 yanc ...
- Python的另一种开发环境--Anaconda中的Spyder
本文作者LucyGill,转载请注明出处(虽然我觉得并不会有人转载). 刚开始学Python的时候,我用的是其自带的idle(安装Python后,在开始菜单里可以找到),后来发现在eclipse中设置 ...
- 银河英雄传说(codevs 1540)
题目描述 Description 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米 ...
- (二)Commonjs规范与模块化
在之前的学习中我们使用require()来引入我们需要的包,这其实就是模块化,各模块相互独立,可以通过某种方式引入别的模块.而这些引入方式都是遵循一定的规范的,这就是CommonJS规范. 一.Com ...
- MongoDB学习day08--Mongoose索引、Mongoose内置方法、扩展Mongoose Model的静态方法和实例方法
一.Mongoose索引 索引是对数据库表中一列或多列的值进行排序的一种结构, 可以让我们查询数据库变得更快. MongoDB 的索引几乎与传统的关系型数据库一模一样, 这其中也包括一些基本的查询优化 ...
- 2018 11.2 PION模拟赛
期望:100 + 50 + 30 = 180 实际:0 + 50 + 30 =80 期望:100 实际:0 数值有负数,边界应该设为-0x7f 此处 gg /* 期望的分:50+ */ ...