linux内核链表的实现

本文会记录一些linux内核实现中使用到的一些小技巧,工具等等,会根据学习进度不定时更新本文......
双向循环链表
第一个想写的是linux的双向循环链表(写这个的原因是因为最近学习epoll的内核代码实现,进而需要了解linux的等待队列,这其中也用到了双向循环链表,稍后也会分析linux的等待队列)
linux的双向循环链表之于传统的双向循环链表,其优点是:将其从具体的数据结构中提取出来构成一种通用的循环链表实现,在linux中表现形式为:
struct list_head {
struct list_head * prev , * next;
}
其常见的使用方法为:若要定义某种特定类型的数据结构的双向循环链表,只需要在结构中包含该struct list_head ,就可以将各个对象链接起来;当对数据结构进行操作(增,删......)的时候,只需要设计针对struct list_head这种通用结构的通用接口即可,不用针对每种具体对象设计不同的接口
典型的结构如下(暂时不会作图,先盗用了等待队列的实现图):

linux内核链表的实现

一般实现一个具体对象的双向循环链表的时候会有一个头节点,只含有struct list_head(假设为struct list_head head;),没有具体对象的信息,若要判断是否队列为空,则只需判断head->prev==head (head->netx == head);具体实现如下:
static inline int list_empty(const struct list_head * head){
return head->next == head;
}

另一个比较很重要的操作就是通过list_head成员获取宿主对象的指针了,这个主要用到了宏:offsetof,container_of
#define offsetof(s,m) (size_t)&(((s *)0)->m)
//s为结构体,m为结构体中的成员,将地址0强制转换为对应的结构体类型,
//而成员m所在的地址减去结构体起始位置即为m在结构体中偏移量,
//此处基地址为0,则成员m所在地址即为偏移量

#define container_of(ptr, type, member) ({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
//作用:获得某成员所在结构体的入口地址
//实现:type为结构题的类型,member为结构体中的一个成员,
//   ptr为指向成员member所属变量类型的一个变量的指针
// 故技重施,(type *)0将地址0强制转换为type结构体类型的地址,
//   typeof( ((type *)0->member)获得了member的类型,
//   接着typeof( ((type *)0->member) * __mptr申明了一个该类型的变量并初始化为ptr的地址;
//   (char *)__mptr将刚刚的地址转换为char* ,offsetof计算出了member成员在结构体中的偏移量,
//   __mptr减去这个偏移刚好就是结构体的起始地址,然后用(type *)强制转换为相应的指针

有关等待队列的数据结构稍后补充......
本文出自 "流离and逍遥" 博客,请务必保留此出处http://liulixiaoyao.blog.51cto.com/1361095/535427

你可能感兴趣的:(linux)