是否有一种有效的方法来查找指定pid的task_struct
,而无需遍历task_struct列表?
答案 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_struct
,find_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!) */
了解有关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
任务的名称空间。