在内核中处理线程的正确方法? [英] Proper way of handling threads in kernel?
问题描述
我已经看到了一些零散的信息,但我似乎无法得出一个最终答案.如何清理内核中的僵尸线程?
I've seen bits of scattered information all around, but I can't seem to get to one final answer. How do you clean up a zombie thread in kernel?
为了确保并产生处理内核中线程的最终正确方法,我想更广泛地提出这个问题.如何在 Linux 内核中创建、终止和清理线程?
Just to make sure, and produce a final correct way of handling threads in kernel, I would like to ask this question more broadly. How do you create, terminate and clean up a thread in the Linux kernel?
到目前为止我所拥有的是:
What I have so far is this:
thread_func:
exited = 0;
while (!must_exit)
do stuff
exited = 1;
do_exit(0)
init_module:
must_exit = 0;
exited = 1;
kthread_run(thread_func, ...) /* creates and runs the thread */
cleanup_module:
must_exit = 1;
while (!exited)
set_current_state(TASK_INTERRUPTIBLE);
msleep(1);
/* How do I cleanup? */
我发现最接近清理解决方案的是 release_task,但我没有找到任何谈论它的地方.我想既然线程函数是 kthread_create
、kthread_run
等,应该有一个 kthread_join
或 kthread_wait
,但是有不是.do_wait
似乎也有可能,但它不需要 struct task_struct *
.
The closest thing I have found to the cleanup solution is release_task, but I didn't find anywhere talking about it. I imagined since the thread functions are kthread_create
, kthread_run
etc, there should be a kthread_join
or kthread_wait
, but there wasn't. do_wait
also seemed likely, but it doesn't take a struct task_struct *
.
此外,我不确定 do_exit
是否是一个好主意,或者是否有必要.有人能提出一个关于如何创建、终止和清理 kthread 的最小草图吗?
Furthermore, I am not sure if do_exit
is a good idea, or if at all necessary either. Can someone please come up with the minimum sketch of how a kthread should be created, terminated and cleaned up?
推荐答案
做到这一点的正确"方法之一是让您的线程函数检查它是否kthread_should_stop
,如果它就返回确实需要停下来.
One of the "right" ways to do this is to have your thread function check if it kthread_should_stop
, and simply return if it does need to stop.
您不需要调用do_exit
,如果您打算从模块退出函数kthread_stop
它,您可能不应该.
You don't need to call do_exit
, and if you intend to kthread_stop
it from the module exit function, you probably shouldn't.
您可以通过查看 kernel/kthread.c
(摘自 Linux 内核 3.3.1):
You can see this by looking at the documentation for kthread_create_on_node
in kernel/kthread.c
(extract from Linux kernel 3.3.1):
/**
* kthread_create_on_node - 创建一个 kthread.
* @threadfn:运行直到signal_pending(current)的函数.
* @data:@threadfn 的数据指针.
* @node:内存节点号.
* @namefmt:线程的 printf 样式名称.
*
* 说明:此辅助函数创建并命名内核
* 线.线程将被停止:使用wake_up_process()启动
* 它.另见 kthread_run().
*
* 如果线程将被绑定在一个特定的 cpu 上,给出它的节点
* 在@node 中,获取 kthread 堆栈的 NUMA 亲和性,否则给出 -1.
* 被唤醒时,线程将运行@threadfn(),@data 作为它的
* 争论.@threadfn() 要么直接调用 do_exit()
* 没有人会调用kthread_stop()的独立线程,或者
* 当'kthread_should_stop()'为真时返回(这意味着
* kthread_stop() 已被调用).返回值应为零
* 或负错误号;它将被传递给 kthread_stop().
*
* 返回一个 task_struct 或 ERR_PTR(-ENOMEM).
*/
/**
* kthread_create_on_node - create a kthread.
* @threadfn: the function to run until signal_pending(current).
* @data: data ptr for @threadfn.
* @node: memory node number.
* @namefmt: printf-style name for the thread.
*
* Description: This helper function creates and names a kernel
* thread. The thread will be stopped: use wake_up_process() to start
* it. See also kthread_run().
*
* If thread is going to be bound on a particular cpu, give its node
* in @node, to get NUMA affinity for kthread stack, or else give -1.
* When woken, the thread will run @threadfn() with @data as its
* argument. @threadfn() can either call do_exit() directly if it is a
* standalone thread for which no one will call kthread_stop(), or
* return when 'kthread_should_stop()' is true (which means
* kthread_stop() has been called). The return value should be zero
* or a negative error number; it will be passed to kthread_stop().
*
* Returns a task_struct or ERR_PTR(-ENOMEM).
*/
kthread_stop
存在匹配"注释:
如果 threadfn() 可以调用 do_exit() 本身,调用者必须确保 task_struct 不会消失.
If threadfn() may call do_exit() itself, the caller must ensure task_struct can't go away.
(我不确定你是怎么做到的——可能是用 get_task_struct
来保持 struct_task
.)
(And I'm not sure how you do that - probably holding on to the struct_task
with a get_task_struct
.)
如果你走线程创建的路径,你会得到类似的东西:
If you walk the path of a thread creation you'll get something like:
kthread_create // macro in kthread.h
-> kthread_create_on_node // in kthead.c
-> adds your thread request to kthread_create_list
-> wakes up the kthreadd_task
kthreadd_task
在reset_init
的init/main.c
中设置.它运行 kthreadd
函数(来自 kthread.c
)
kthreadd_task
is set up in init/main.c
in reset_init
. It runs the kthreadd
function (from kthread.c
)
kthreadd // all in kthread.c
-> create_kthread
-> kernel_thread(kthread, your_kthread_create_info, ...)
而 kthread
函数本身就是:
kthread
-> initialization stuff
-> schedule() // allows you to cancel the thread before it's actually started
-> if (!should_stop)
-> ret = your_thread_function()
-> do_exit(ret)
... 所以如果 your_thread_function
只是简单地返回,do_exit
将使用它的返回值被调用.无需自己动手.
... So if your_thread_function
simply returns, do_exit
will be called with its return value. No need to do it yourself.
这篇关于在内核中处理线程的正确方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!