您的位置:首页 > 其它

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 结构的数据结构的遍历的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: