关于task_struct列表:
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
task_t *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
我正在使用这些指针来运行进程的子进程。 我不明白(并且很难从内核代码中理解)是最年轻的子列表是以null结尾还是循环?
我是否可以浏览所有p_cptr
,直到我NULL
,或者我是否应该再次回到原点?
答案 0 :(得分:1)
请尝试以下代码。我没有在内核2.4上测试它(仅在4.0上),但我认为它应该适用于2.4而几乎没有修改。我使用kthreadd
进程作为父进程,例如,因为它有很多子进程。
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/list.h>
#define KTHREADD_PID 2
static int __init ktdf_init(void)
{
struct task_struct *kthreadd_task;
struct list_head *list;
/* Find kthreadd task by PID */
kthreadd_task = pid_task(find_vpid(KTHREADD_PID), PIDTYPE_PID);
pr_debug("Process name: %s\n", kthreadd_task->comm);
/* Iterate over all children of kthreadd_task */
list_for_each(list, &kthreadd_task->children) {
struct task_struct *task;
/* Get next child */
task = list_entry(list, struct task_struct, sibling);
pr_debug(" Child name: %s\n", task->comm);
}
return 0;
}
static void __exit ktdf_exit(void)
{
}
module_init(ktdf_init);
module_exit(ktdf_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("kthreadd children finder module");
MODULE_LICENSE("GPL");
正如您所看到的,.sibling
list是circular doubly-linked list,这意味着此列表的最后一个元素(tail)指向第一个元素(head)。您可以从list_for_each()宏实现中看到它。
dmesg
中的输出(模块由insmod
加载后):
Process name: kthreadd
Child name: ksoftirqd/0
Child name: ksoftirqd/1
Child name: ksoftirqd/2
Child name: ksoftirqd/3
Child name: kworker/0:0
Child name: kworker/0:0H
Child name: kworker/0:1
Child name: kworker/0:1H
Child name: kworker/0:2
...
您可以通过ps
命令进行检查:
$ ps auxf
这给了我相同的过程树:
[kthreadd]
\_ [ksoftirqd/0]
\_ [ksoftirqd/1]
\_ [ksoftirqd/2]
\_ [ksoftirqd/3]
\_ [kworker/0:0]
\_ [kworker/0:0H]
\_ [kworker/0:1]
\_ [kworker/0:1H]
\_ [kworker/0:2]
...
答案 1 :(得分:0)
至少在2.4.18
中,您感兴趣的两个列表都不是循环的(即由p_cptr
字段组成的列表,以及由{{1}组成的列表}}和p_ysptr
字段)。
我从p_osptr
do_fork
(主叉例程)kernel/fork.c中找到的一些代码中推断出:
p = alloc_task_struct();
...
*p = *current;
...
p->p_cptr = NULL;
...
SET_LINKS(p);
在生成新生儿过程的同时,我们为其分配task_struct
,并将父进程的task_struct
复制到其中。
第三行使用p_cptr
终止NULL
列表。
SET_LINKS
中定义了#define SET_LINKS(p) do { \
...
(p)->p_ysptr = NULL; \
if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
(p)->p_osptr->p_ysptr = p; \
(p)->p_pptr->p_cptr = p; \
...
} while (0)
:
SET_LINKS
新生儿始终是最小的孩子,所以当p_ysptr
将NULL
设置为NULL
时,它会SET_LINKS
终止最小的孩子(兄弟姐妹列表)
如果新生儿不是第一个(即最老的)孩子,那么p_osptr
不会更改最大的孩子的(p)->p_pptr->p_cptr
。
但如果新生儿是第一个孩子,NULL
仍然是(p)->p_osptr = (p)->p_pptr->p_cptr
p_osptr
已执行,因此第一个孩子(最大的孩子)的NULL
设置为SET_LINKS
。
因此,NULL
也会使用time_lag
终止列表中最早的子端。