gpt4 book ai didi

multithreading - kthread 停止而不运行

转载 作者:行者123 更新时间:2023-12-03 13:02:00 29 4
gpt4 key购买 nike

如果我使用 kthread_run 创建内核线程然后 kthread_stop它立即,内核线程可能会停止而不运行。我查看了kthread_run的源代码和 kthread_stop在 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;
}
看来内核线程应该在 kthread_stop之前就已经被唤醒了返回,但可能不会。我真的很困惑,有人可以帮助我吗?
我的测试代码如下。
测试1.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)
生成文件
obj-m += test1.o

all:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=`pwd`

clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=`pwd` clean
要运行的命令
sudo insmod test1.ko
sudo rmmod test1
第一次运行的 dmesg
[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 之前已经执行过,这次停止了。
第二次运行的 dmesg
[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 没有运行就停止了。但是没有立即停止的t1和t3在停止之前运行。

最佳答案

(此答案对应于 Linux 内核版本 5.4。)
新创建的内核线程任务执行函数kthread在“内核/kthread.c”中。如果一切顺利kthread调用kthread_run引用的线程函数的(或 kthread_create 的)threadfn范围。但是,最后测试之前调用了threadfn函数指针是检查内核线程的KTHREAD_SHOULD_STOP少量。如果KTHREAD_SHOULD_STOP位已设置,threadfn函数指针不会被调用,新的内核线程任务会调用do_exit退出代码 -EINTR .函数末尾的相关代码kthread如下:

    ret = -EINTR;
if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) {
cgroup_kthread_ready();
__kthread_parkme(self);
ret = threadfn(data);
}
do_exit(ret);
虽然 kthread_run返回前唤醒新创建的内核线程任务,有可能为 kthread_stop要调用的函数并设置内核线程的 KTHREAD_SHOULD_STOP在内核线程到达其 KTHREAD_SHOULD_STOP 的最终检查之前的位在调用 threadfn 之前的位函数指针。在这种情况下,内核线程将在没有 threadfn 的情况下退出。函数指针一直被调用。
OP的原代码可以改成打印 kthread_stop的返回值如下:
    int exit_code;

/* ... */
printk("Stopping t2\n");
exit_code = kthread_stop(t2);
printk("t2 stopped, exit code %d\n", exit_code);
然后它应该显示线程 t2退出代码 -EINTR (可能是 -4 )如果它在入口函数 func 之前停止被称为。

关于multithreading - kthread 停止而不运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65987208/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com