Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
  2. kthread_stop(struct task_struct *thread) - if included in module exit function, causes kernel panic since thread was already terminated after executing once

Is this a correct approach? if not please suggest

like image 817
Raxesh Oriya Avatar asked Jun 10 '19 07:06

Raxesh Oriya


1 Answers

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:

    static DECLARE_COMPLETION(thread_done);
    

    (There is also a DECLARE_COMPLETION_ONSTACK macro for use when the completion structure variable is on the stack.)

    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 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. If it is guaranteed that nothing will wait for completion later, the 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(&thread_done, 0);
    

    Calling complete_and_exit(...) is safer than separate calls to complete(...) and 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. Calling complete_and_exit(...) avoids that happening because the function exists outside the module code and never returns.

  5. Ensure the thread has finished

    To ensure that the thread has finished, call 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. In either case, it is no longer running any of the module code, so it is safe to continue.

like image 176
Ian Abbott Avatar answered Oct 24 '22 04:10

Ian Abbott