简体   繁体   English

使用“return”或“do_exit()”终止内核线程是一个好习惯吗?

[英]Is it a good practice to terminate kernel thread with “return” or “do_exit()”?

My objective is to execute kernel thread from my driver's probe function only ONCE which performs firmware downloading. 我的目标是仅从我的驱动程序的探测功能执行内核线程,执行固件下载。

Putting up sample code(not actual one) for simplicity, 为简单起见,提供示例代码(非实际代码)

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kthread.h>

MODULE_LICENSE("GPL");

struct task_struct *kthread;


static int thread_func(void* data)
{
    printk("In %s function\n", __func__);
    return 0;
}

static int hello_init(void)
{
    int ret = 0;

    printk("Hello World\n");
    kthread = kthread_run(thread_func,
            NULL, "kthread-test");
    if (IS_ERR(kthread)) {
        ret = PTR_ERR(kthread);
        printk("Unable to run kthread err %d\n", ret);
        return ret;
    }
    return 0;
}


static void hello_exit(void)
{
    printk("Bye World\n");

}

I am not using any of following because: 我没有使用以下任何一种,因为:

  1. kthread_should_stop() - used for continuous execution which I do not want kthread_should_stop() - 用于我不想要的连续执行
  2. kthread_stop(struct task_struct *thread) - if included in module exit function, causes kernel panic since thread was already terminated after executing once kthread_stop(struct task_struct *thread) - 如果包含在模块退出函数中,则导致内核崩溃,因为线程在执行一次后已经终止

Is this a correct approach? 这是正确的方法吗? if not please suggest 如果没有请建议

You need to ensure that thread has gone away before the module exit function returns. 在模块退出函数返回之前,您需要确保线程已经消失。 One way to do that is by using a "completion" structure. 一种方法是使用“完成”结构。

The basic idea is to initialize the completion structure before starting the thread, make the thread mark the completion structure as "complete" when it exits, and have the module exit function (or whatever) wait for the completion structure to be marked as complete. 基本思想是在启动线程之前初始化完成结构,使线程在完成时将完成结构标记为“完成”,并使模块退出函数(或其他)等待完成结构标记为完成。

  1. Prerequisites 先决条件

     #include <linux/completion.h> 
  2. Initialize the completion structure 初始化完成结构

    If the completion structure variable is statically allocated, it can be initialized in the variable definition using the DECLARE_COMPLETION macro: 如果静态分配完成结构变量,则可以使用DECLARE_COMPLETION宏在变量定义中初始化它:

     static DECLARE_COMPLETION(thread_done); 

    (There is also a DECLARE_COMPLETION_ONSTACK macro for use when the completion structure variable is on the stack.) (当完成结构变量在堆栈上时,还有一个DECLARE_COMPLETION_ONSTACK宏。)

    Alternatively, an uninitialized struct completion can be defined (for example as a member of a dynamically allocated structure) and initialized subsequently by calling init_completion(...) : 或者,可以定义未初始化的struct completion (例如,作为动态分配的结构的成员),然后通过调用init_completion(...)初始化:

     struct completion thread_done; ... init_completion(&thread_done); 
  3. Create the thread 创建线程

     kthread = kthread_run(thread_func, NULL, "kthread-test"); if (IS_ERR(kthread)) { complete(&thread_done); /* <-- may or may not be required */ ret = PTR_ERR(kthread); return ret; } 

    In the above, if kthread_run(...) fails, the completion structure is marked as "complete" in case some code waits for completion later. 在上面,如果kthread_run(...)失败,则在某些代码稍后等待完成的情况下,将完成结构标记为“完成”。 If it is guaranteed that nothing will wait for completion later, the complete(&thread_done); 如果保证以后没有任何东西等待完成,则complete(&thread_done); call can be omitted. 呼叫可以省略。

  4. Exit the thread 退出线程

    Rather than returning from the thread function or calling do_exit(...) , the thread should call complete_and_exit(...) to mark the thread as "complete": 线程应调用complete_and_exit(...)将线程标记为“完成”,而不是从线程函数返回或调用do_exit(...)

     complete_and_exit(&thread_done, 0); 

    Calling complete_and_exit(...) is safer than separate calls to complete(...) and do_exit(...) . 调用complete_and_exit(...)complete(...)do_exit(...)单独调用更安全。 With separate calls to complete(...) and do_exit(...) there is a possibility that the module code will have already been unloaded when complete(...) returns, so the thread could execute non-existent or random code. 通过单独调用complete(...)do_exit(...)有可能在complete(...)返回时已经卸载了模块代码,因此线程可以执行不存在的或随机的代码。 Calling complete_and_exit(...) avoids that happening because the function exists outside the module code and never returns. 调用complete_and_exit(...)可以避免发生这种情况,因为函数存在于模块代码之外并且永远不会返回。

  5. Ensure the thread has finished 确保线程已完成

    To ensure that the thread has finished, call wait_for_completion(...) : 要确保线程已完成,请调用wait_for_completion(...)

     wait_for_completion(&thread_done); 

    On return, the thread will have either exited already or it is still running in the call to complete_and_exit(...) and is about to exit. 返回时,线程已经退出或者仍然在调用complete_and_exit(...)仍在运行,并且即将退出。 In either case, it is no longer running any of the module code, so it is safe to continue. 在任何一种情况下,它都不再运行任何模块代码,因此可以安全地继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM