概述
最近在看《linux内核设计与实现》【陈莉君】,其中关于linux遍历子进程的叙述如下:
struct task_struct *task;
struct list_head *list;
list_for_each(list,¤t->children)
{
task=list_entry(list,structtask_struct,sibling);
}
初次阅读时感觉很不理解,后经细细琢磨,方知原来如此,下面是我个人的理解,以与诸君探讨。
1、进程亲属关系的成员
struct tast_struct {
/* real parent process */
struct task_struct *real_parent;
/* recipient of SIGCHLD, wait4() reports */
struct task_struct *parent;
/* list of my children */
struct list_head children;
/* linkage in my parent's children list */
struct list_head sibling;
/* threadgroup leader */
struct task_struct *group_leader;
}
2、linux内核的链表操作
/*------------------------------------------------
* list_for_each(/include/linux/list.h)
*----------------------------------------------*/
#define list_for_each(pos,head)
for(pos=(head)->next; pos!=head;pos=pos->next)
/*------------------------------------------------
* list_entry(/include/linux/list.h)
*----------------------------------------------*/
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
/*------------------------------------------------
* container_of(include/linux/kernel.h)
*----------------------------------------------*/
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
/*------------------------------------------------
* offsetof(/include/linux/stddef.h)
*----------------------------------------------*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
3、下面来解释linux遍历子进程的原理
list_for_each(list,¤t->children)
@list
是指向struct list_head类型的指针,故它可以指向进程描述符中的children或者sibling
@current
当前正在执行的进程
先对list_for_each宏做如下格式替换
#define list_for_each(list,head)
for(list=(¤t->children)->next; list!=¤t->children; list=list->next)
再对list_entry进行宏替换
struct task_struct *task;
struct list_head *list;
list_for_each(list,¤t->children)
{
task=container_of(list,struct task_struct,sibling);
}
可以看到进程中的children和sibling有潜在的关系,我们再来看他们二者的关系。
在task_struct结构体中有对成员sibling的注释为
structlist_head sibling; // linkage in my parent’schildren list
直译过来是该指针存放本进程的父进程的子进程的list.
某网站上有段英文解释:
In order to organize data as linked list using struct
list_head you have to declare list root and declare
the same type (struct list_head). children entry of struct task_struct entry is a root. sibling entry of
sibling are used. Usage of list_for_each for children means what children is a root. Usage of list_entry for
sibling means what sibling is a list entry.
该段的大意是指在一个循环链表中,children指向链表头,sibling指向链表的链表项。
Linux进程家族关系图如下
通过上述解说及图示理解,container_of定义中,首先将通过list_for_each获得的list_head类型的指针赋予一个临时定义的变量__mptr,存放了该子进程在父进程的子进程list中的位置,其实也就是该子进程的task_struct结构体中的sibling指针,而后通过offsetof获得偏移量之后,通过减法关系,即获得了该子进程的task_struct的指针。
最后
以上就是怕黑萝莉为你收集整理的linux遍历子进程浅析的全部内容,希望文章能够帮你解决linux遍历子进程浅析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复