如何立即取消Linux内核模块中工作队列的工作项? [英] How to immediately cancel a work item of a workqueue in a Linux kernel module?

查看:466
本文介绍了如何立即取消Linux内核模块中工作队列的工作项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

内核模块代码:

#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>

MODULE_LICENSE("GPL");

static struct workqueue_struct *queue;

static void work_func(struct work_struct *work)
{
    int i = 0;
    while (i < 5) {
        printk(KERN_INFO "%d\n", i);
        usleep_range(1000000, 1000001);
        i++;
    }
}

DECLARE_WORK(work, work_func);

int init_module(void)
{
    queue = create_workqueue("myworkqueue");
    queue_work(queue, &work);
    return 0;
}

void cleanup_module(void)
{
    cancel_work_sync(&work);    
    destroy_workqueue(queue);
}

如果我这样做:

insmod mymod.ko
rmmod mymod

rmmod挂在cancel_work_sync上,它首先等待工作完成,直到计数结束.

rmmod hangs on cancel_work_sync, which first waits for the work to finish, until the counting is over.

是否可以立即取消该工作项目?

Is it possible to immediately cancel that work item?

最小的可运行示例此处.

在Linux内核4.9中进行了测试.

Tested in Linux kernel 4.9.

推荐答案

原子控制变量

我找不到在工作队列中停止工作的方法,但是使用简单的控制变量是一种可能的解决方案.

I could not find a way to stop work in a workqueue, but using a simple control variable is a possible solution.

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */
#include <linux/workqueue.h>

MODULE_LICENSE("GPL");

static struct workqueue_struct *queue;
static atomic_t run = ATOMIC_INIT(1);

static void work_func(struct work_struct *work)
{
    int i = 0;
    while (atomic_read(&run)) {
        printk(KERN_INFO "%d\n", i);
        usleep_range(1000000, 1000001);
        i++;
        if (i == 10)
            i = 0;
    }
}

DECLARE_WORK(work, work_func);

int init_module(void)
{
    queue = create_workqueue("myworkqueue");
    queue_work(queue, &work);
    return 0;
}

void cleanup_module(void)
{
    atomic_set(&run, 0);
    destroy_workqueue(queue);
}

kthread kthread_stop

kthread kthread_stop

工作队列是基于kthreads的,在该示例中,工作队列基本上是无用的,因此我们可以直接使用kthreads.

Work queues are based on kthreads, and a work queue is basically useless in that example, so we could use the kthreads directly.

kthread_stop等待线程返回.

另请参阅:

  • Proper way of handling threads in kernel?
  • How to wait for a linux kernel thread (kthread)to exit?

kthread中的信号处理似乎是一个争论的主题,现在不可能了:

Signal handling in kthreads seems to have been a polemic subject, and is now not possible: https://unix.stackexchange.com/questions/355280/how-signals-are-handled-in-kernel

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static struct task_struct *kthread;

static int work_func(void *data)
{
    int i = 0;
    while (!kthread_should_stop()) {
        printk(KERN_INFO "%d\n", i);
        usleep_range(1000000, 1000001);
        i++;
        if (i == 10)
            i = 0;
    }
    return 0;
}

int init_module(void)
{
    kthread = kthread_create(work_func, NULL, "mykthread");
    wake_up_process(kthread);
    return 0;
}

void cleanup_module(void)
{
    kthread_stop(kthread);
}

计时器

直接在中断上下文中运行,因此更准确,但更受限制.

Run in interrupt context directly, so more accurate, but more restricted.

另请参见:如何在Linux内核设备驱动程序中使用计时器?

See also: How to use timers in Linux kernel device drivers?

#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>

MODULE_LICENSE("GPL");

static void callback(unsigned long data);
static unsigned long onesec;

DEFINE_TIMER(mytimer, callback, 0, 0);

static void callback(unsigned long data)
{
    pr_info("%u\n", (unsigned)jiffies);
    mod_timer(&mytimer, jiffies + onesec);
}

int init_module(void)
{
    onesec = msecs_to_jiffies(1000);
    mod_timer(&mytimer, jiffies + onesec);
    return 0;
}

void cleanup_module(void)
{
    del_timer(&mytimer);
}

这篇关于如何立即取消Linux内核模块中工作队列的工作项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆