linux 通过pid查找task_struct的高效方法

oug3syen  于 2023-11-17  发布在  Linux
关注(0)|答案(4)|浏览(135)

有没有一种有效的方法可以找到指定PID的task_struct,而无需迭代task_struct列表?

bqf10yzr

bqf10yzr1#

使用以下方法之一有什么错?

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);

字符串

x8diyxa7

x8diyxa72#

如果你想从一个模块中找到task_structfind_task_by_vpid(pid_t nr)等是不起作用的,因为这些函数没有导出。
在模块中,您可以使用以下函数:

#include <linux/sched.h>
#include <linux/pid.h>
// ...
struct task_struct *my_task;
my_task = pid_task(find_vpid(pid), PIDTYPE_PID);

字符串

uwopmtnx

uwopmtnx3#

有一个更好的方法可以从模块中获取task_struct的示例。总是尝试使用 Package 函数/助手例程,因为它们是以这样一种方式设计的,如果驱动程序员遗漏了什么,内核可以自己处理。例如错误处理,条件检查等。

/* 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(),并正确地处理并发。这就是为什么我上面说总是使用这种 Package 器的原因。
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);


在内核模块中,你也可以通过以下方式使用 Package 器函数:

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


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

juzqafwq

juzqafwq4#

没有人提到**pid_task()函数和从它得到的指针应该在RCU临界区内使用**(因为它使用了RCU保护的数据结构),否则可能会出现释放后使用BUG
在Linux内核源代码中有很多使用pid_task()的情况(例如,在posix_timer_event()中)。
举例来说:

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.你也可以使用特殊的API函数,如rcu_read_lock()下的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任务的命名空间进行搜索。

相关问题