关于list_for_each_entry相关函数
offsetof宏
定义:
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
该宏先将0
转换成TYPE
型指针,即形成一个指向地址0
的TYPE
指针,然后对TYPE
中的MEMBER
成员进行取址,而整个TYPE
结构体的起始地址是0
,那么这里取得的MEMBER
的地址实际上等同于在TYPE
中的相对偏移量。
container_of
定义:
/**
* 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) );})
可以看到container_of
被预定义成一个函数,它首先通过((type *)0)->member
定义member
类型的指针__mptr
,这个指针指向ptr
,获取到了我们所要求的结构体所包含的member
的地址,然后(char *)__mptr - offsetof(type, member)
,通过member
成员的地址减去它在结构体中的偏移量,然后强制转换成type
指针就得到了这个结构体的地址,define
预定义返回最后一句表达式的值,将所求结构体指针返回。
总结一下,container_of
的功能就是通过一个指向结构体成员member
的指针,求得指向整个结构体的指针。
list_entry
定义:
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of\
(ptr,type,member)
从定义中可以看到,list_entry
其实是container_of
的一个别名而已,完全等同
list_for_each_entry
定义:
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
这里强调一下双向链表及链表头的概念,建立一个双向链表通常有一个独立的用于管理链表的链表头,链表头一般不包含实体数据的,必须使用INIT_LIST_HEAD()
进行初始化,表头建立后,就可以将带有数据结构的实体链表成员加入到链表张。关系如图所示。
list_for_each_entry
被预定义为一个for
循环语句,for
循环的第一句获取(head)->next
指向的member
成员的结构体指针,将pos
初始化为链表中出链表头之外的第一个实体链表成员,for
的第三句通过pos->member.next
指针遍历整个实体链表,当pos->member.next
再次指向链表头的时候,说明已经遍历完毕,退出循环。
list_for_each_entry_safe
定义:
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
相比于list_for_each_entry
,list_for_each_entry_safe
用指针n
对链表的对下一个数据结构进行了临时存储,所以如果在遍历链表的时候可能要删除链表的当前项,用list_for_each_entry_safe
可以安全的删除,而不会影响接下来的遍历过程。