If I create a kernel thread with kthread_run
then kthread_stop
it immediately, the kernel thread might be stopped without running. I checked the source code of kthread_run
and kthread_stop
in Linux-5.4.73
/** * kthread_run - create and wake a thread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: Convenient wrapper for kthread_create() followed by * wake_up_process(). Returns the kthread or ERR_PTR(-ENOMEM). */#define kthread_run(threadfn, data, namefmt, ...) \({ \ struct task_struct *__k \ = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ if (!IS_ERR(__k)) \ wake_up_process(__k); \ __k; \})
/** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */int kthread_stop(struct task_struct *k){ struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); set_bit(KTHREAD_SHOULD_STOP, &kthread->flags); kthread_unpark(k); wake_up_process(k); wait_for_completion(&kthread->exited); ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret;}
It seems that the kernel thread should have been waken up before kthread_stop
return, but it might not. I am really confused, could anybody help me?
My test code is as follows.
test1.c
#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/kthread.h>#include <linux/sched.h>#include <linux/semaphore.h>#include <linux/spinlock.h> MODULE_LICENSE("GPL");static struct task_struct *t1;static struct task_struct *t2;static struct task_struct *t3;static int func(void *__para){ const char *msg = (const char *)__para; printk("%s %s\n", __func__, msg); /* Wait for kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); printk("%s %s return\n", __func__, msg); return 0;}static int __init start_init(void){ printk(KERN_INFO "Thread Creating...\n"); t1 = kthread_run(func, "t1", "t1"); if (IS_ERR(t1)) { WARN_ON(1); return 0; } t2 = kthread_run(func, "t2", "t2"); if (IS_ERR(t2)) { WARN_ON(1); return 0; } printk("Stopping t2\n"); kthread_stop(t2); printk("t2 stopped\n"); t3 = kthread_run(func, "t3", "t3"); if (IS_ERR(t3)) { WARN_ON(1); return 0; } return 0;}static void __exit end_exit(void){ printk(KERN_INFO "Cleaning Up...\n"); if (IS_ERR(t1)) return; printk("Stopping t1\n"); kthread_stop(t1); printk("t1 stopped\n"); printk("Stopping t3\n"); kthread_stop(t3); printk("t3 stopped\n");}module_init(start_init)module_exit(end_exit)
Makefile
obj-m += test1.oall: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=`pwd`clean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=`pwd` clean
The command to run
sudo insmod test1.kosudo rmmod test1
The dmesg of the first run
[10914.046211] Thread Creating...[10914.046515] func t1[10914.046530] Stopping t2[10914.046531] func t2[10914.046533] func t2 return[10914.046538] t2 stopped[10914.046555] func t3[10938.895544] Cleaning Up...[10938.895545] Stopping t1[10938.895552] func t1 return[10938.895561] t1 stopped[10938.895562] Stopping t3[10938.895566] func t3 return[10938.895587] t3 stopped
t2 has executed before stopped this time.
The dmesg of the second run
[10940.775771] Thread Creating...[10940.776109] func t1[10940.776126] Stopping t2[10940.776138] t2 stopped[10940.776162] func t3[10956.375606] Cleaning Up...[10956.375607] Stopping t1[10956.375613] func t1 return[10956.375674] t1 stopped[10956.375674] Stopping t3[10956.375678] func t3 return[10956.375697] t3 stopped
t2 stopped without running. But t1 and t3 which are not stopped immediately run before being stopped.