很幸运,第一次接触kernel,就认识了这么重要的结构:list_head,它作为结构体数据的成员无处不在,它是双向链表,通过它可以得到它所在的结构体数据的地址。
list.h
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
list_entry是通过list_head地址得到它所嵌入的结构体数据的地址。
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer. list_head结构体指针
* @type: the type of the struct this is embedded in. list_head所在的结构体数据的类型
* @member: the name of the list_head within the struct. list_head在这个结构体数据中的变量名
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
具体定义在:
kernel.h
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
现在理解这块宏定义就容易了,ptr是list_head指针,__mptr是结构体数据类型的list_head这个成员变量的地址,offsetof是根据结构体数据的类型和成员变量计算出成员变量在结构体数据类型中的偏移,成员变量地址减去它在结构体中的偏移就是结构体数据的地址!