linux内核中延迟的工作delayed_work
转载:linux内核中延迟的工作delayed_work_千册的博客-CSDN博客
前言
本次实验逻辑依然很简单,count数到5。如果发现代码不能执行,那是不可能的。如果真的不能执行,也让我学习学习。
对于周期性的任务,除了定时器以外,在Linux内核中还可以利用一套封装得很好的快捷机制,其本质是利用工作队列和定时器实现,这套快捷机制就是delayed_work,delayed_work结构体的定义如下所示。
它的成员里有工作队列和定时器。这就是定时器的封装应用啊。为了以后读内核代码的时候,看到这个东西不心虚,决定还是再最后做一个小实验,我坚信大部分人都可以自己使用定时器实现这么一个东西出来。
#include <linux/workqueue.h> struct delayed_work { struct work_struct work; struct timer_list timer; /* target workqueue and CPU ->timer uses to queue ->work */ struct workqueue_struct *wq; int cpu; };
一 struct delayed_work
我们可以通过如下函数调度一个delayed_work在指定的延时后执行:
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
当指定的delay到来时,delayed_work结构体中的work成员work_func_t类型成员func()会被执行。work_func_t类型定义为:
typedef void (*work_func_t)(struct work_struct *work);
其中,delay参数的单位是jiffies,因此一种常见的用法如下:
schedule_delayed_work(&work, msecs_to_jiffies(poll_interval));
msecs_to_jiffies()用于将毫秒转化为jiffies。如果要周期性地执行任务,通常会在delayed_work的工作函数中再次调用schedule_delayed_work(),周而复始。如下函数用来取消delayed_work:
int cancel_delayed_work(struct delayed_work *work); int cancel_delayed_work_sync(struct delayed_work *work);
二 相关宏和函数介绍
INIT_DELAYED_WORK
这个宏里做了很多事情,所以不要自己给struct delayed_work变量赋值。
#define INIT_DELAYED_WORK(_work, _func) \ __INIT_DELAYED_WORK(_work, _func, 0)
#define __INIT_DELAYED_WORK(_work, _func, _tflags) \ do { \ INIT_WORK(&(_work)->work, (_func)); \ __setup_timer(&(_work)->timer, delayed_work_timer_fn, \ (unsigned long)(_work), \ (_tflags) | TIMER_IRQSAFE); \ } while (0)
schedule_delayed_work
1 /** 2 * schedule_delayed_work - put work task in global workqueue after delay 3 * @dwork: job to be done 4 * @delay: number of jiffies to wait or 0 for immediate execution 5 * 6 * After waiting for a given time this puts a job in the kernel-global 7 * workqueue. 8 */ 9 static inline bool schedule_delayed_work(struct delayed_work *dwork, 10 unsigned long delay) 11 { 12 return queue_delayed_work(system_wq, dwork, delay); 13 }
cancel_delayed_work
1 /** 2 * cancel_delayed_work - cancel a delayed work 3 * @dwork: delayed_work to cancel 4 * 5 * Kill off a pending delayed_work. 6 * 7 * Return: %true if @dwork was pending and canceled; %false if it wasn't 8 * pending. 9 * 10 * Note: 11 * The work callback function may still be running on return, unless 12 * it returns %true and the work doesn't re-arm itself. Explicitly flush or 13 * use cancel_delayed_work_sync() to wait on it. 14 * 15 * This function is safe to call from any context including IRQ handler. 16 */ 17 bool cancel_delayed_work(struct delayed_work *dwork) 18 { 19 unsigned long flags; 20 int ret; 21 22 do { 23 ret = try_to_grab_pending(&dwork->work, true, &flags); 24 } while (unlikely(ret == -EAGAIN)); 25 26 if (unlikely(ret < 0)) 27 return false; 28 29 set_work_pool_and_clear_pending(&dwork->work, 30 get_work_pool_id(&dwork->work)); 31 local_irq_restore(flags); 32 return ret; 33 } 34 EXPORT_SYMBOL(cancel_delayed_work);
cancel_delayed_work_sync
1 /** 2 * cancel_delayed_work_sync - cancel a delayed work and wait for it to finish 3 * @dwork: the delayed work cancel 4 * 5 * This is cancel_work_sync() for delayed works. 6 * 7 * Return: 8 * %true if @dwork was pending, %false otherwise. 9 */ 10 bool cancel_delayed_work_sync(struct delayed_work *dwork) 11 { 12 return __cancel_work_timer(&dwork->work, true); 13 } 14 EXPORT_SYMBOL(cancel_delayed_work_sync);
三 测试例程
源码:csi_timer.c
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/types.h> 4 #include <linux/kernel.h> 5 #include <linux/slab.h> 6 #include <linux/workqueue.h> 7 8 #define DEBUG_CT(format,...)\ 9 printk("%s:%s:%d: "format"\n",\ 10 __FILE__,__func__,__LINE__,\ 11 ##__VA_ARGS__) 12 13 struct ct_dev_{ 14 int count; 15 struct delayed_work my_delayed_work; 16 }; 17 struct ct_dev_ *ct_dev; 18 19 static void ct_work_func_t(struct work_struct *pwork) 20 { 21 struct delayed_work *pd = (struct delayed_work*) 22 container_of(pwork,struct delayed_work,work); 23 24 struct ct_dev_ *p = (struct ct_dev_*) 25 container_of(pd,struct ct_dev_,my_delayed_work); 26 DEBUG_CT("p->count = %d",p->count++); 27 if(p->count < 5){ 28 schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000)); 29 } 30 } 31 32 static int __init ct_init(void) 33 { 34 struct ct_dev_ *p = NULL; 35 ct_dev = (struct ct_dev_ *)kmalloc(sizeof(struct ct_dev_),GFP_KERNEL); 36 if(IS_ERR(ct_dev)){ 37 DEBUG_CT("kmalloc error"); 38 return -ENOMEM; 39 } 40 p = ct_dev; 41 DEBUG_CT(""); 42 p->count = 0; 43 DEBUG_CT(""); 44 INIT_DELAYED_WORK(&p->my_delayed_work, ct_work_func_t); 45 schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000)); 46 47 DEBUG_CT("init ok"); 48 return 0; 49 } 50 static void __exit ct_exit(void) 51 { 52 struct ct_dev_ *p = ct_dev; 53 if(IS_ERR(p)){ 54 return; 55 } 56 DEBUG_CT("p->count = %d",p->count++); 57 cancel_delayed_work_sync(&p->my_delayed_work); 58 kfree(p); 59 DEBUG_CT("exit ok"); 60 } 61 module_init(ct_init); 62 module_exit(ct_exit); 63 MODULE_LICENSE("GPL"); 64 65
Makefile
1 export ARCH=arm 2 export CROSS_COMPILE=arm-linux-gnueabihf- 3 4 KERNELDIR := /home/lkmao/imx/linux/linux-imx 5 CURRENT_PATH := $(shell pwd) 6 FILE_NAME=csi_timer 7 obj-m := $(FILE_NAME).o 8 9 build: kernel_modules 10 11 kernel_modules: 12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules 13 sudo cp $(FILE_NAME).ko /big/nfsroot/jiaocheng_rootfs/home/root/ 14 clean: 15 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
测试结果:
root@hehe:~# insmod csi_timer.ko [ 22.024402] /big/csi_driver/csi_timer/csi_timer.c:ct_init:41: [ 22.030262] /big/csi_driver/csi_timer/csi_timer.c:ct_init:43: [ 22.036256] /big/csi_driver/csi_timer/csi_timer.c:ct_init:47: init ok root@hehe:~# [ 23.033240] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 0 [ 24.033238] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 1 [ 25.033249] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 2 [ 26.033240] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 3 [ 27.033235] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 4
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)