在Linux 2.4中,最小的子列表是cylic?

时间:2015-05-05 09:58:13

标签: c linux list linux-kernel kernel

关于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,或者我是否应该再次回到原点?

2 个答案:

答案 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_ysptrNULL设置为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终止列表中最早的子端。