首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何立即取消Linux内核模块中工作队列的工作项?

如何立即取消Linux内核模块中工作队列的工作项?
EN

Stack Overflow用户
提问于 2017-05-15 07:21:39
回答 2查看 2.8K关注 0票数 0

内核模块代码:

代码语言:javascript
复制
#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);
}

如果我这样做了:

代码语言:javascript
复制
insmod mymod.ko
rmmod mymod

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

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

最小可运行示例这里

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

EN

回答 2

Stack Overflow用户

发布于 2020-11-30 09:24:51

还有一种方法可以用信号来阻止线程。这种方法比您的更好,因为它不需要线程定期醒来并使用kthread_should_stop()轮询停止变量。没有浪费CPU时间,它允许您的线程睡觉,只要它需要。

代码语言:javascript
复制
static int kthread_handle(void *param)
{
    allow_signal(SIGINT);
    allow_signal(SIGKILL);

    for (;;)
    {
        // ...
        // Some blocking functions such as kernel_read()/kernel_write()
        // ...
        if (signal_pending(current))
        {
            goto end;
        }

        // ...
        // Some interruptible functions
        // ...
        if (mutex_lock_interruptible(...) == -EINTR)
        {
            goto end;
        }
    }

end:
    while (!kthread_should_stop())
    {
        schedule();
    }

    return 0;
}

static int __init drv_init(void)
{
    // Create and start kernel thread
    kthread = kthread_run(kthread_handle, NULL, "kthread");

    return 0;
}

static void __exit drv_exit(void)
{
    send_sig(SIGKILL, kthread, 1);
    kthread_stop(kthread);
}

module_init(drv_init);
module_exit(drv_exit);

我不知道如何向工作队列发送信号,所以到目前为止,解决方案只适用于k线程。

票数 1
EN

Stack Overflow用户

发布于 2017-05-16 08:28:09

原子控制变量

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

代码语言:javascript
复制
#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_stop

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

kthread_stop等待线程返回。

另请参阅:

线程中的信号处理似乎是一个有争议的主题,现在不可能了:https://unix.stackexchange.com/questions/355280/how-signals-are-handled-in-kernel

代码语言:javascript
复制
#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);
}

定时器

直接在中断上下文中运行,这样更准确,但更受限制。

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

代码语言:javascript
复制
#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);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43973583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档