C 如何立即取消Linux内核模块中工作队列的工作项?
内核模块代码:C 如何立即取消Linux内核模块中工作队列的工作项?,c,linux,linux-kernel,C,Linux,Linux Kernel,内核模块代码: #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)
#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);
}
rmmod
挂起cancel\u work\u sync
,它首先等待工作完成,直到计数结束
是否可以立即取消该工作项
最小可运行示例
在Linux内核4.9中测试。原子控制变量 我无法找到停止工作队列中的工作的方法,但使用简单的控制变量是一种可能的解决方案
#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);
}
计时器
直接在中断上下文中运行,因此更准确,但更受限制
另见:
#包括
#包括
#包括
#包括
模块许可证(“GPL”);
静态无效回调(无符号长数据);
静态无符号长一秒;
定义_定时器(mytimer,callback,0,0);
静态无效回调(无符号长数据)
{
pr_信息(“%u\n”,(未签名)jiffies);
mod_定时器(&mytimer,jiffies+onesec);
}
int init_模块(void)
{
一秒=毫秒到毫秒(1000);
mod_定时器(&mytimer,jiffies+onesec);
返回0;
}
空洞清理_模块(空洞)
{
del_定时器(&mytimer);
}
还有另一种方法可以通过信号停止kthread。这种方法比您的好,因为它不需要您的线程定期唤醒并使用kthread_should_stop()轮询stop变量。不浪费CPU时间,它允许线程在需要时休眠
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);
我不知道如何向工作队列发送信号,因此目前的解决方案仅适用于kthreads。我认为您应该使用“取消工作”而不是“取消工作同步”。@rk1825谢谢!由于某些原因,我在重新编译后的插入时得到了“未知符号取消工作”,但它编译得很好!我将查看相关线程。@rk1825该符号显然未导出:即使您将找到非等待替换的
cancel\u work\u sync
,destroy\u workqueue()。因此,您的模块不会发生任何更改。(实际上,您可以省略模块中的取消\u工作\u同步()
调用)?是否要在执行模块的某个函数时卸载该模块?这会崩溃。或者,您是否希望在卸载模块时中断函数的执行,使其在卸载后不再继续?如果是这样,那就完全不同了。他们都可以睡觉,这意味着没有办法立即取消工作。@0安德烈:是的,这也是我发现的。我只发布尽可能接近我想做的事情的例子。
#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);
}
#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);
}
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);