在Linux系统中大量使用了双向链表这一数据结构。一般的想法是在使用双向链表数据结构的时候:
typedef struct page
{
struct page *prev;
struct page *next;
.........
}page
typedef struct node
{
struct node *prev;
struct node *next;
.........
}page
这样每次使用一个结构体的时候,都需要定义一个双向链表,确实非极大的浪费资源,在毛德操的《情景分析》一书是这样描述的:
Linux内核中采用了一套通用的,一般的,可以用到各种不同数据结构的队列操作,为此,代码的作者把指针prev和next从具体的“宿主”数据结构中抽象出来称为一种数据结构list_head
成为数据结构的一个“连接件”,也可以独立存在成为一个队列的头。
struct list_head
{
struct list_head *next,*prev;
}
这样在具体的使用时就不一样的,如下,页面管理的Page数据结构为例,其定义为:(include/linux/mm.h)
typedef struct page
{
struct list_head *next,*prev;
........
struct page *next_hash;
........
struct list_head lru;
........
}page
在每个结构体内部都寄宿了list_head这个结构体,这样对该结构体的初始化可以使用宏定义INIT_LIST_HAED 来实现,定义如下:
#define INIT_LIST_HAED(ptr) do{(ptr)->next = (ptr);(ptr)->prev = (ptr);}while(0)
关于这个宏定义do{(ptr)->next = (ptr);(ptr)->prev = (ptr);}while(0)其实挺有意思的,do-while
语句是先执行一次在判断因此上面这个语句就是执行完{}里面后退出,调用一次这个宏定义,就会执行一次里面的代码。
接着说这个代码的含义:
#define LIST_HEAD_INIT(name) { &(name), &(name) } //就是用head的地址初始化其两个成员next和prev ,使其都指向自己。
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
要把page结构体通过其“队列头”list链入一个队列,使用list_add(),这是一个Inline函数,
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
//这个函数在head节点后面插入new节点。
`
这个inline函数内部又调用了一个inline函数__list_add()来完成操作:
/**
* __list_add - Insert a new entry between two known consecutive entries.
* @new:
* @prev:
* @next:
*
* This is only for internal list manipulation where we know the prev/next
* entries
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev, struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
对于知道队列我们可以进行add或者del操作,但是如果我们进去的一个队列其中的一项的时候,又该如何找到宿主结构呢?
看下面这个代码
page = memlist_entry(curr,struct page ,list);
这段代码,curr是list_head类型的结构体,函数把curr换算成宿主结构的起始地址,也就是其指向宿主的结构的指针。
#define list_entry(ptr,typr,member) (type*)((char*)(ptr)-(unsigned long)(&((type*0)->member)))