前言

本次实验逻辑依然很简单,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

/*** schedule_delayed_work - put work task in global workqueue after delay* @dwork: job to be done* @delay: number of jiffies to wait or 0 for immediate execution** After waiting for a given time this puts a job in the kernel-global* workqueue.*/
static inline bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay)
{return queue_delayed_work(system_wq, dwork, delay);
}

cancel_delayed_work

/*** cancel_delayed_work - cancel a delayed work* @dwork: delayed_work to cancel** Kill off a pending delayed_work.** Return: %true if @dwork was pending and canceled; %false if it wasn't* pending.** Note:* The work callback function may still be running on return, unless* it returns %true and the work doesn't re-arm itself.  Explicitly flush or* use cancel_delayed_work_sync() to wait on it.** This function is safe to call from any context including IRQ handler.*/
bool cancel_delayed_work(struct delayed_work *dwork)
{unsigned long flags;int ret;do {ret = try_to_grab_pending(&dwork->work, true, &flags);} while (unlikely(ret == -EAGAIN));if (unlikely(ret < 0))return false;set_work_pool_and_clear_pending(&dwork->work,get_work_pool_id(&dwork->work));local_irq_restore(flags);return ret;
}
EXPORT_SYMBOL(cancel_delayed_work);

cancel_delayed_work_sync

/*** cancel_delayed_work_sync - cancel a delayed work and wait for it to finish* @dwork: the delayed work cancel** This is cancel_work_sync() for delayed works.** Return:* %true if @dwork was pending, %false otherwise.*/
bool cancel_delayed_work_sync(struct delayed_work *dwork)
{return __cancel_work_timer(&dwork->work, true);
}
EXPORT_SYMBOL(cancel_delayed_work_sync);

三 测试例程

源码:csi_timer.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/workqueue.h>#define DEBUG_CT(format,...)\printk("%s:%s:%d: "format"\n",\__FILE__,__func__,__LINE__,\##__VA_ARGS__)struct ct_dev_{int count;struct delayed_work my_delayed_work;
};
struct ct_dev_ *ct_dev;static void ct_work_func_t(struct work_struct *pwork)
{struct delayed_work *pd = (struct delayed_work*)container_of(pwork,struct delayed_work,work);struct ct_dev_ *p = (struct ct_dev_*)container_of(pd,struct ct_dev_,my_delayed_work);DEBUG_CT("p->count = %d",p->count++);if(p->count < 5){schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000));}
}static int __init ct_init(void)
{struct ct_dev_ *p = NULL;ct_dev = (struct ct_dev_ *)kmalloc(sizeof(struct ct_dev_),GFP_KERNEL);if(IS_ERR(ct_dev)){DEBUG_CT("kmalloc error");return -ENOMEM;}p = ct_dev;DEBUG_CT("");p->count = 0;DEBUG_CT("");INIT_DELAYED_WORK(&p->my_delayed_work, ct_work_func_t);schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000));DEBUG_CT("init ok");return 0;
}
static void __exit ct_exit(void)
{struct ct_dev_ *p = ct_dev;if(IS_ERR(p)){return;}DEBUG_CT("p->count = %d",p->count++);cancel_delayed_work_sync(&p->my_delayed_work);kfree(p);DEBUG_CT("exit ok");
}
module_init(ct_init);
module_exit(ct_exit);
MODULE_LICENSE("GPL");

Makefile

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-KERNELDIR := /home/lkmao/imx/linux/linux-imx
CURRENT_PATH := $(shell pwd)
FILE_NAME=csi_timer
obj-m := $(FILE_NAME).obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modulessudo cp $(FILE_NAME).ko /big/nfsroot/jiaocheng_rootfs/home/root/
clean:$(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

linux内核中延迟的工作delayed_work相关推荐

  1. Linux内核中makefile有什么作用?深入解析makefile工作过程和原理

    Table of Contents Makefile 中的变量 常用的变量有以下几类: 1) 版本信息 2) CPU 体系结构:ARCH 3) 路径信息:TOPDIR, SUBDIRS 4) 内核组成 ...

  2. Linux内核中的软中断、tasklet和工作队列详解

    本文基于Linux2.6.32内核版本. 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom half)演 ...

  3. Linux内核中的软中断、tasklet和工作队列具体解释

    [TOC] 本文基于Linux2.6.32内核版本号. 引言 软中断.tasklet和工作队列并非Linux内核中一直存在的机制,而是由更早版本号的内核中的"下半部"(bottom ...

  4. 【CXL】cxl-cli、ndctl、daxctl管理linux内核中NVDIMM设备子系统

    Intel不断在存储器这边布局: Intel于 2019 年 4 月发布了傲腾持久性内存(Optane DC persistent memory),这是目前市场上唯一商用的持久性内存(Pmem)存储设 ...

  5. linux内核中的jiffies,Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

    在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构 struct timeval { time_t tv_s ...

  6. 简单谈一点linux内核中套接字的bind机制--数据结构以及端口确定

    众所周知,创建一个套接字可以bind到一个特定的ip地址和端口,实际上套接字这一概念代表了TCP/IP协议栈的应用层标识,协议栈中的应用层就是通过一个ip地址和一个端口号标识的,当然这仅仅是对于TCP ...

  7. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  8. TCP三次握手在linux内核中的实现

    TCP三次握手在linux内核中的实现 以下基于linux内核2.4.0源码(转自www.yuanma.org/) 以前一直使用的网络通讯的函数都是工作在阻塞模式.在看connect实现源码时,突然想 ...

  9. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

最新文章

  1. 把二元查找树转变成排序的双向链表
  2. grunt入门讲解1:grunt的基本概念和使用
  3. CString::Format
  4. 基础-简单的深度优先遍历
  5. 的garch预测_随机森林预测
  6. 接口测试基础——第5篇xlrd模块
  7. RabbitMQ和Kafka的显著差异(3)
  8. ajax手机号码验证,Jquery Validation 插件验证手机号
  9. Mongodb添加超级管理员和普通用户
  10. 计算机网络笔记 韩立刚(物理层+数据链路层+网络层+传输层已完成)
  11. python数字时钟
  12. 计算机硬件中内存的作用是什么,内存是什么 内存条的作用到底是什么
  13. 报考软件资格考试过程详解--附学习分享
  14. winword.exe应用程序错误0xc0000142
  15. 【图】爱情公寓里你最喜欢谁?爱情公寓3的投票,快来参加哦。
  16. WPS 2010 页眉下方添加下划线
  17. C语言编程>第二十一周 ② 请补充main 函数,该函数的功能是:把一维数组中的元素逆置,结果仍然保存在原数组中。
  18. python里π怎么打_python里的π怎么输入
  19. 缓冲区溢出的基本原理
  20. 争议中的云算力市场 |链捕手

热门文章

  1. 阿里云轻量应用服务器最新价格表2023版(2核8G/4核8G/4核16G/8核16G/8核32G)
  2. 选择树结构带出父级节点,展示在另外一处
  3. Mysql价格降低20%应该怎么写_mysql优化建议20条
  4. 袋鼠云携手阿里云,打造梦想小镇马拉松大数据指挥中心
  5. Java多线程的sleep(休眠)
  6. wait与notify的使用
  7. JeeSite 框架学习笔记
  8. 如何压缩视频文件大小,只需三步!
  9. css 边缘闪光_CSS_用CSS控制的闪烁效果,  一段文本或一张图片,它 - phpStudy...
  10. 丝绸之路也可以是科技传播之路