在linux中使用计时器停止内核线程

在linux中使用计时器停止内核线程,linux,timer,kernel,linux-device-driver,Linux,Timer,Kernel,Linux Device Driver,我试图通过在计时器将调用的函数中调用kthread_stop()来停止内核线程。当我将此模块加载到内核中时,kthread在计时器中提到的指定时间之后启动和停止,但它在日志中给出了一些错误消息 有人能帮我解决这个问题吗?因为我是内核线程编程新手。这是我的代码 #include <linux/kernel.h> #include <linux/module.h> #include <linux/timer.h> #include <linux/kthrea

我试图通过在计时器将调用的函数中调用kthread_stop()来停止内核线程。当我将此模块加载到内核中时,kthread在计时器中提到的指定时间之后启动和停止,但它在日志中给出了一些错误消息

有人能帮我解决这个问题吗?因为我是内核线程编程新手。这是我的代码

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/kthread.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
struct task_struct *task;
static struct timer_list my_timer;
int thread_function(void *data) {
    printk(KERN_ALERT"IN THREAD FUNCTION");
    while(!kthread_should_stop()){
    schedule();
    }
printk(KERN_ALERT"after schedule\n");
return 1;
}

void my_timer_callback( unsigned long data ){
printk( "my_timer_callback called (%ld).\n", jiffies );
printk(KERN_ALERT"THREAD STOPPED\n");
kthread_stop(task);
}

int init_module( void ){
    int ret;
    printk("Timer module installing\n");

    //my_timer.function, my_timer.data
    setup_timer( &my_timer, my_timer_callback, 0 );

    printk( "Starting timer to fire in 2000ms (%ld)\n", jiffies );
    ret = mod_timer( &my_timer, jiffies + msecs_to_jiffies(2000) );
    if (ret) printk("Error in mod_timer\n");
    printk(KERN_INFO"-------------------- THREAD START------------------------");

    task = kthread_run(thread_function,NULL,"kerneltthread");
    printk(KERN_ALERT"Kernel Thread Name: %s\n",task->comm);

    return 0;
}

void cleanup_module( void ){
    int ret;

    ret = del_timer( &my_timer );
    if (ret) printk("The timer is still in use...\n");

    printk("Timer module uninstalling\n");

    return;
}

 MODULE_LICENSE("GPL");

计时器的功能是在softirq上下文中执行的,因为它不应该睡眠。但是您的
my\u timer\u回调
调用
kthread\u stop
函数,该函数一直等到kthread完成,即sleep


因此,
原子调度
错误出现:函数休眠,但由于原子上下文的原因,它不应该这样做。

我不确定该错误是否可能重复,但init_模块函数似乎有问题。您正在添加一个带有未初始化expires字段的计时器,并且仅在该计时器之后才设置expires字段。我建议您调用init_timer,然后设置expires、function和data,最后调用add_timer。否则会有一个短时间的伪计时器,可能会在您不期望的情况下调用它。在这种情况下,waitqueue也更合适,而不是在等待计时器函数执行时重复调用schedule()。但另一方面,当函数为_atomic()时返回一个正数。您的线程不应被允许执行睡眠/调用计划。您应该向线程引入检查,以查找在这种上下文中运行的位置。
kthread\u stop
停止线程,但它应该从进程上下文调用(与原子上下文相反)。您可以使用,例如,
延迟工作
Aug  5 16:35:31 brao kernel: Timer module installing
Aug  5 16:35:31 brao kernel: Starting timer to fire in 2000ms (4299209850)
Aug  5 16:35:31 brao kernel: -------------------- THREAD             START------------------------
Aug  5 16:35:31 brao kernel: Kernel Thread Name: kerneltthread
Aug  5 16:35:31 brao kernel: IN THREAD FUNCTION
Aug  5 16:35:33 brao kernel: my_timer_callback called (4299211856).
Aug  5 16:35:33 brao kernel: THREAD STOPPED
Aug  5 16:35:33 brao kernel: BUG: scheduling while atomic: swapper/3/0/0x10000100
Aug  5 16:35:33 brao kernel: after schedule