9

linux/sched.h所以我知道如何通过简单地包含和使用以下代码来创建内核并线性迭代进程:

struct task_struct *task;

for_each_process(task)
{
   printk("Name: %s PID: [%d]\n", task->comm, task->pid);
}

如何使用深度优先搜索打印这些任务?我希望我的输出类似于ps -eLf.

已提供以下代码补丁以供参考:

struct task_struct *task;
struct list_head *list;
list_for_each(list, &init_task->children) {
    task = list_entry(list, struct task_struct, sibling);
    /* task points to the next child in the list */
}

我知道它会task->comm返回名称并task->pid返回该任务的 PID。

哪些字段用于状态和父 PID?

4

4 回答 4

9

这有点老了,但我遇到了它,因为它似乎是操作系统概念第 9 版第 3 章中的编程项目之一,所以其他人可能会来找。

您开始使用的代码直接来自书中,但它是一个很好的起点。您只需要实现 DFS。这是完成它的代码,它应该很容易解释:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>

/**
 * Performs a DFS on a given task's children.
 *
 * @void
 */
void DFS(struct task_struct *task)
{   
    struct task_struct *child;
    struct list_head *list;

    printk("name: %s, pid: [%d], state: %li\n", task->comm, task->pid, task->state);
    list_for_each(list, &task->children) {
        child = list_entry(list, struct task_struct, sibling);
        DFS(child);
    }
}

/**
 * This function is called when the module is loaded. 
 *
 * @return 0  upon success
 */ 
int task_lister_init(void)
{
    printk(KERN_INFO "Loading Task Lister Module...\n");
    DFS(&init_task);

    return 0;
}

/**
 * This function is called when the module is removed.
 *
 * @void
 */
void task_lister_exit(void)
{
    printk(KERN_INFO "Removing Task Lister Module...\n");
}

// Macros for registering module entry and exit points.
module_init(task_lister_init);
module_exit(task_lister_exit);
于 2015-12-29T21:59:46.747 回答
1

你可以得到状态task->state /* -1 unrunnable, 0 runnable, >0 stopped */

获取父pidtask->parent->pid

于 2013-10-06T15:41:49.520 回答
0

对于 uid、tgid 可以参考 task_struct 中的 cred 结构。对于优先级,您可以参考 rt_priority(实时优先级)和 prio 字段。对于其他字段,您可以参考 proc 目录(因为 ps 将从 proc 获取输入)。

于 2014-08-25T12:36:45.133 回答
0

我看到接受的答案是使用递归。即使代码更简单,在内核代码中编写递归函数仍然是一个非常糟糕的主意。内核的可用堆栈大小有限,递归函数很容易溢出并使一切崩溃。您应该迭代地实现 DFS/BFS:维基百科页面(DFSBFS)有解释和代码示例。

struct这是一个使用支持作为队列的简单 DFS 和 BFS 实现(在内核 5.10 上测试)。由于迭代 DFS 和 BFS 之间的唯一区别是分别将新元素推送到队列的头部或尾部,我只是实现了两者,您可以通过简单地添加#define BFS.

// Uncomment to use BFS instead of DFS
// #define BFS

static void dump_children_tree(struct task_struct *task) {
    struct task_struct *child;
    struct list_head *list;
    struct queue *q, *tmp;
#ifdef BFS
    struct queue **tail;
#endif
    pid_t ppid;

    q = kmalloc(sizeof *q, GFP_KERNEL);
    if (!q)
        goto out_nomem;

    q->task = task;
    q->next = NULL;
#ifdef BFS
    tail = &q->next;
#endif

    while (q) {
        task = q->task;
#ifndef BFS
        tmp = q;
        q = q->next;
        kfree(tmp);
#endif

        rcu_read_lock();
        ppid = rcu_dereference(task->real_parent)->pid;
        rcu_read_unlock();

        pr_info("Name: %-20s State: %ld\tPID: %d\tPPID: %d\n",
            task->comm,
            task->state,
            task->pid,
            ppid
        );

        list_for_each(list, &task->children) {
            child = list_entry(list, struct task_struct, sibling);
            get_task_struct(child);

            tmp = kmalloc(sizeof *tmp, GFP_KERNEL);
            if (!tmp)
                goto out_nomem;

            tmp->task = child;
#ifdef BFS
            tmp->next = NULL;
            *tail = tmp;
            tail = &tmp->next;
#else // DFS
            tmp->next = q;
            q = tmp;
#endif
        }

        put_task_struct(task);
#ifdef BFS
        tmp = q;
        q = q->next;
        kfree(tmp);
#endif
    }

    return;

out_nomem:
    while (q) {
        tmp = q;
        q = q->next;
        kfree(tmp);
    }
}

注意:上述函数假定get_task_struct()已在传递的 上调用,并在返回之前task自动调用它。put_task_struct()

于 2022-02-06T00:35:32.007 回答