您的位置:首页 > 运维架构 > Linux

linux遍历子进程浅析

2016-06-20 22:30 766 查看
最近在看《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 kernel