首先我们先看一下list_head的定义,该结构体在linux/types.h中定义。
[cpp]
structlist_head {
structlist_head *next, *prev;
};
list_head很简单,其实就是一个双向链表,但是我们也许会奇怪,这样的双向链表能干什么,它里面连最起码的一个泛化指针(void*)都没有,也就是说我们不可能通过它来获得其他对象的引用,那有什么用呢?也许,让我们来定义list_head,我们也许会这样定义:
[cpp]
structhongchangfirst_list_head {
structlist_head *next, *prev;
void*general_pointer;
};
这样我们就可以随心所欲的建立我们需要的任何数据结构的双向链表了。但是Linux内核毕竟不是”一般人“写出来的,所以人家就可以用刚才那种定义来实现任何数据结构的双向链表,它是怎么实现的呢?要明白这个问题,我们还得看看其它的一些结构体。
首先我们看一下list_for_each,它在linux/list.h中定义,我们可以看到它只是一个宏定义。
[cpp]
#define list_for_each(pos, head) \
for(pos = (head)->next; pos != (head); pos = pos->next)
其中head是list_head组成的双向链表的指针,因为一般来说list_head双向链表都是循环双向链表,所以head就定义了你从哪里开始遍历这个链表,而pos就是指向list_head的指针,用来具体的对每一个list_head进行操作。用这个宏我们就可以实现对一个循环双向链表的完整遍历一遍。
如果只有这个遍历又有什么用呢,我们怎么得到我们想要的相关数据结构引用呢?关键是我们还得有list_entry,它其实就是一个从list_head到一个拥有该list_head字段的“包含体”的入口宏定义,我们先看看这个宏定义,具体在linux/list.h中定义。
[cpp]
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
其实list_entry就是直接使用了container_of,那我们就得看看container_of 了,具体在linux/kernel.h里定义。关于它的详细理解请参考。
[cpp]
#define container_of(ptr, type, member) ({ \
consttypeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char*)__mptr - offsetof(type,member) );})
其中ptr是指向包含体成员的指针,比如指向list_head的指针,type就是包含该成员(比如list_head字段)的”包含体“类型,member是该成员(比如list_head)在该包含体类型中具体的名字。它的返回值是一个指向type的指针。