kernel:通过pid查找task_struct的有效方法?

时间:2011-12-17 19:25:46

标签: process kernel

是否有一种有效的方法来查找指定pid的task_struct,而无需遍历task_struct列表?

4 个答案:

答案 0 :(得分:12)

使用以下哪种方法有什么问题?

extern struct task_struct *find_task_by_vpid(pid_t nr);
extern struct task_struct *find_task_by_pid_ns(pid_t nr,
            struct pid_namespace *ns);

答案 1 :(得分:11)

如果您想从模块中找到task_structfind_task_by_vpid(pid_t nr)等不会起作用,因为这些功能不会被导出。

在模块中,您可以使用以下功能:

pid_task(find_vpid(pid), PIDTYPE_PID);

答案 2 :(得分:3)

有一种更好的方法可以从模块中获取task_struct的实例。 总是尝试使用包装函数/辅助程序例程,因为它们的设计方式是,如果驱动程序程序员遗漏了某些内容,则内核可以自行处理。例如-错误处理,条件检查等。

/* Use below API and you will get a pointer of (struct task_struct *) */

taskp = get_pid_task(pid, PIDTYPE_PID);

并获取pid_t类型的PID。您需要使用以下API-

find_get_pid(pid_no);

在调用这些API时,您无需使用“ rcu_read_lock()”和“ rcu_read_unlock()”,因为“ get_pid_task() >“在调用” pid_task()“之前内部调用rcu_read_lock(),rcu_read_unlock()并正确处理并发。这就是为什么我上面说的总是使用此类包装器的原因。

下面的get_pid_task()和find_get_pid()函数的片段:-

struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
    struct task_struct *result;
    rcu_read_lock();
    result = pid_task(pid, type);
    if (result)
        get_task_struct(result);
    rcu_read_unlock();
    return result;
}
EXPORT_SYMBOL_GPL(get_pid_task);

struct pid *find_get_pid(pid_t nr)
{
    struct pid *pid;

    rcu_read_lock();
    pid = get_pid(find_vpid(nr));
    rcu_read_unlock();

    return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);

在内核模块中,您还可以通过以下方式使用包装器功能-

taskp = get_pid_task(find_get_pid(PID),PIDTYPE_PID);

PS:有关API的更多信息,请查看kernel / pid.c

答案 3 :(得分:1)

没有人提到在RCU关键部分内使用pid_task()函数和指针(从中获取)(因为它使用了RCU) -受保护的数据结构)。 否则,可能会有免费使用后的BUG
在Linux内核源代码中(例如,在posix_timer_event()中使用pid_task()的情况很多。
例如:

rcu_read_lock();
/* search through the global namespace */
task = pid_task(find_pid_ns(pid_num, &init_pid_ns), PIDTYPE_PID);
if (task)
    printk(KERN_INFO "1. pid: %d, state: %#lx\n",
           pid_num, task->state); /* valid task dereference */
rcu_read_unlock(); /* after it returns - task pointer becomes invalid! */

if (task)
    printk(KERN_INFO "2. pid: %d, state: %#lx\n",
           pid_num, task->state); /* may be successful,
                                   * but is buggy (task dereference is INVALID!) */

Kernel.org

了解有关RCU API的更多信息

P.S。您也可以只使用rcu_read_lock()下的特殊API函数,例如find_task_by_pid_ns()find_task_by_vpid()

第一个用于搜索特定的名称空间:

task = find_task_by_pid_ns(pid_num, &init_pid_ns); /* e.g. init namespace */

第二个用于搜索current任务的名称空间。