list_for_each(pos, head)、list_for_each_entry(pos, head, member)
2018-01-18 15:05
543 查看
一、list_head
Linux 内核定义了 list_head 数据结构,字段 next 和 prev 分别表示通用双向链表向前和向后的指针元素。不过,值得特别关注的是,list_head 字段的指针中存放的是另一个 list_head 字段的地址,而不是含有 list_head 结构的整个数据结构地址用 list_head 数据结构构造的一个双向链表如下所示:
二、list_for_each(pos, head)
list.h/** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)
由上可知,这个宏是对表头地址 head 指定的链表进行扫描,在每次循环时,通过 pos 返回指向链表元素的 list_head 结构的指针。这个的实现很简单,没有什么需要详细说明的
三、list_for_each_entry(pos, head, member)
list.h/** * 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_first_entry(head, typeof(*pos), member); \ &pos->member != (head); \ pos = list_next_entry(pos, member))
这个宏与 list_for_each 类似,但是返回包含了 list_head 结构的数据结构的地址,而不是 list_head 结构本身的地址
下面就来详细看一下这是怎么实现的,我们就拿遍历父进程 father 的 children 链表来举例,那么 head 即为 &father->children,member 即为 sibling
3.1 list_first_entry(ptr, type, member)
list.h/** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member)
结合例子,即相当于 list_entry((&father->children)->next, type, member),所以 for 循环的初始化即为:
pos = list_entry((&father->children)->next, type, member)
3.2 list_entry(ptr, type, member)
list.h/** * 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. */ 9f1d #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) );})
即相当于 pos = container_of((&father->children)->next, type, member),那么第一行即为:
const list_head *__mptr = (&father->children)->next;
第二行即为:
(task_struct *)( (char *)__mptr - offsetof(task_struct, sibling) );
即相当于 __mptr 指向的地址减去 sibling 在 task_struct 中的偏移,再转化为 (task_struct *) 类型的指针
用方程组的思想来理解 container_of 的作用即为:
x->member = ptr,求 x 是多少,代入例子中即为:
x->sibling = (&father->children)->next,返回 x
我们再来看一下 task_struct 结构体中 children 与 sibling 的关系,如下图所示:
由上图可以看出:
Child 的 sibling 指向的地址实际在 Parent 的 children 指向的双向链表中
当调用 list_entry((&father->children)->next, type, member) 时,实际就会返回指向 Child1 的指针
3.3 list_next_entry(pos, member)
list.h/** * list_next_entry - get the next element in list * @pos: the type * to cursor * @member: the name of the list_struct within the struct. */ #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member)
由上可以看出 list_next_entry 也是通过 list_entry 实现的,代入例子就是:
list_entry((Child1)->sibling.next, task_struct, sibling)
也就是返回指向 Child2 的指针
综上所述,list_for_each_entry(pos, head, member) 就是通过这样的方式实现对包含了 list_head 结构的数据结构的遍历的
相关文章推荐
- list_for_each_entry(pos, head, member)的内幕
- linux核list_for_each_entry(pos, head, member)分析
- Linux内核中list_head、list_for_each、list_entry、container_of之间的关系
- linux内核学习笔记之——list_for_each_entry
- 比list_entry更简洁的写法list_for_each_entry
- linux内核学习笔记之——list_for_each_entry
- 关于container_of和list_for_each_entry 及其相关函数的分析
- Linux 双链表 list_for_each_entry 实现
- list_for_each_entry/list_entry/container_of
- 关于container_of和list_for_each_entry 及其相关函数的分析
- list_for_each_entry
- list_for_each_entry_continue()与list_for_each_entry_from()的区别
- 内核常见函数之list_for_each_entry/container_of
- linux内核学习笔记之——list_for_each_entry
- 关于list_for_each_entry
- 关于container_of和list_for_each_entry 及其相关函数的分析
- linux内核学习笔记之——list_for_each_entry
- list_for_each_entry分析
- 详解Linux内核之双向循环链表(2) list_for_each/list_entry/list_for_each_entry
- 关于container_of和list_for_each_entry 及其相关函数的分析