Linux内核链表 ——list相关内容

来源:互联网 发布:淘宝网不登录不能搜索 编辑:程序博客网 时间:2024/06/03 17:50

1  链表数据结构的定义:

struct list_head {struct list_head *next, *prev;};

list_head结构包含两个指向list_head结构的指针prev和next,内核的链表具备双链表功能,实际上,通常它都组织成双循环链表。
这里的list_head没有数据域。在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点

2   声明和初始化链表

#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
LIST_HEAD_INIT初始化链表next、prev指针都为指向自己,因为Linux用头指针的next是否指向自己来判断链表是否为空:

static inline int list_empty(const struct list_head *head){return head->next == head;}
3  宏定义操作


#define list_entry(ptr, type, member) /      container_of(ptr, type, member)  

#define container_of(ptr, type, member) ({                      /          const typeof( ((type *)0)->member ) *__mptr = (ptr);    /          (type *)( (char *)__mptr - offsetof(type,member) );})  
先把0强制类型转换成为指向一个type型数据空间的指针,然后取其中的成员member,通过typeof得到这个成员member的类型,然后定义一个指向这个类型数据的指针命名为__mptr,并赋值为ptr;

把上面得到的__mptr减去成员member的偏移量,然后在强制类型转换成指向type型空间的指针,也就是地址,也就是得到了type类型的首地址,也就得到了一个指针,可以用它做“->”运算,得到其结构体中的任意一个值

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  

先把0强制类型转换成为指向一个TYPE型数据的指针,然后取其中的MEMBER成员,再取它的地址,最后再强制类型转换成size_t型,就是unsigned long型,也就是MEMBER成员的地址,而该TYPE型数据的首地址为0,所以这个地址也就是MEMBER成员的偏移量,所以offsetof得到的是TYPE类型数据中成员MEMBER的地址偏移量

list_entry,ptr从一个结构的成员指针找到其容器的指针,ptr是找容器的那个变量的指针,把它减去自己在容器中的偏移量的值就应该 得到容器的指针。(容器就是包含自己的那个结构)

#define list_first_entry(ptr, type, member) /      list_entry((ptr)->next, type, member) 
它是调用了list_entry来定义的,就是找到ptr->next的地址,也就是第一节点的地址

下面给出一些定义,根据上面的内容很容易看懂

#define list_for_each(pos, head) /      for (pos = (head)->next; prefetch(pos->next), pos != (head); /              pos = pos->next)  #define __list_for_each(pos, head) /      for (pos = (head)->next; pos != (head); pos = pos->next) 

#define list_for_each_prev(pos, head) /      for (pos = (head)->prev; prefetch(pos->prev), pos != (head); /              pos = pos->prev)