Linux 如何将 task_list 转换为 list_head?

问题描述

我正在尝试编写一个函数,该函数对除主进程外的子进程的 pid 进行递归求和(如果 C 是 B 的儿子,而 B 是 A 的儿子,那么我想要 pid(B)+pid(C))

所以我写道:

int get_children_sum_internal(const struct task_struct *current) {
    int result = current->pid;
    struct list_head *pos;
    list_for_each(pos,&current->children)
    {
        result+=pos->pid;
    }
    return result;
}

asmlinkage int get_children_sum(void) {
    if (list_empty(&current->children))
    {
        return;
    }
    return get_children_sum_internal(current);
}

但是我收到一个错误,因为 current 来自 task_list 类型而 pos 来自 list_head 类型。我该如何解决这个问题?

解决方法

您遇到的一个问题(可能是也可能不是唯一的问题)是,在您的 list_for_each 中,pos 的类型是 list_head,但随后您将其用作task_struct 通过访问 pos->pid。您需要首先使用 task_struct 函数获取包含 pos 的封装子 container_of()

从定义 include/linux/kernel.hcontainer_of() 开始:

/**
 * 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) ({ 

因此,在您的情况下,我认为执行 container_of(pos,task_struct,sibling) 将返回孩子的 task_struct,然后您可以访问其 pid。请注意,我使用了 sibling 而不是 children,因为在这一步,观点是从孩子的角度来看的。从孩子的角度来看,它位于兄弟列表中,从父母的角度来看,它是它的孩子列表。 (有关更多说明,请参阅 this)。


更新:OP 编辑​​了帖子中的代码以使用 list_entry,而之前使用 pid 访问 pos->pidlist_entry 函数是另一种获取封装对象的有效方法。 Behind the sceneslist_entry 无论如何都会调用 container_of