前言

15. 定时器

本章内容为驱动基石之一。

驱动只提供功能,不提供策略。

原文:https://www.cnblogs.com/lizhuming/p/14922233.html

参考源码路径:include\linux\timer.h

参考例子就明白如何使用了。

15.1 内核函数汇总

KERNEL 使用。

说明:以下只是给出部分 API 而已。为 Linux5.12.8 版本。还有其它 API 可以实现内核定时器功能,具体参考内核文档。

  • setup_timer(): 设置定时器。
  • add_timer(): 向内核添加定时器。
  • mod_timer(): 修改定时器超时时间。
  • del_timer(): 删除定时器。

15.2 内核滴答

获取 CONFIG_HZ:

  1. 在 Linux 内核源码根目录上找到 .config 配置文件。打开该文件找到宏 CONFIG_HZ ,该宏定义了内核滴答(tick)频率。
  2. 命令行:进入 /boot,查找文件 config-5.8.0-53-geberic(各个系统,文件名不一样,看前缀即可) 内容。
  • 如命令:grep ^CONFIG_HZ /boot/config-$(uname -r) 。
  1. APP:sysconf(_SC_CLK_TCK) 。

内核 tick:

每跳动一次,内核全局值 jiffies 就会累加 1。

定时器的时间值就是基于 jiffies 的。

所以,其实也可以比较设定的 滴答值 和 jiffies 来判断是否超时。由此,内核推荐使用以下 4 个 API:

/*
* These inlines deal with timer wrapping correctly. You are
* strongly encouraged to use them
* 1. Because people otherwise forget
* 2. Because if the timer wrap changes in future you won't have to
* alter your driver code.
*
* time_after(a,b) returns true if the time a is after time b.
*
* Do this with "<0" and ">=0" to only test the sign of the result. A
* good compiler would generate better code (and a really good compiler
* wouldn't care). Gcc is currently neither.
*/
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((b) - (a)) < 0))
#define time_before(a,b) time_after(b,a) #define time_after_eq(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((a) - (b)) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a)

15.3 相关结构体

timer_list:

struct timer_list {
/*
* All fields that change during normal runtime grouped to the
* same cacheline
*/
struct hlist_node entry;
unsigned long expires; // 超时时间
void (*function)(struct timer_list *); // 回调函数
u32 flags; // 标志 #ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};

15.4 setup_timer() 设置定时器

功能:设置定时器。初始化 timer_list 结构体。

函数原型:

/**
* timer_setup - prepare a timer for first use
* @timer: the timer in question
* @callback: the function to call when timer expires
* @flags: any TIMER_* flags
*
* Regular timer initialization should use either DEFINE_TIMER() above,
* or timer_setup(). For timers on the stack, timer_setup_on_stack() must
* be used and must be balanced with a call to destroy_timer_on_stack().
*/
#define timer_setup(timer, callback, flags) \
__init_timer((timer), (callback), (flags))

15.5 add_timer() 向内核添加定时器

功能:向内核添加定时器。

函数原型:

/**
* add_timer - start a timer
* @timer: the timer to be added
*
* The kernel will do a ->function(@timer) callback from the
* timer interrupt at the ->expires point in the future. The
* current time is 'jiffies'.
*
* The timer's ->expires, ->function fields must be set prior calling this
* function.
*
* Timers with an ->expires field in the past will be executed in the next
* timer tick.
*/
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
__mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
}
EXPORT_SYMBOL(add_timer);

15.6 mod_timer() 修改定时器超时时间

功能:修改定时器超时时间。

注:注释说明中,修改超时时间相当于删除定时器再重新添加到内核。说明,在添加到内核后就不能简单的使用 imer->expires = expires; 来修改超时时间啦。

函数原型:

/**
* mod_timer - modify a timer's timeout
* @timer: the timer to be modified
* @expires: new timeout in jiffies
*
* mod_timer() is a more efficient way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
*
* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
*
* Note that if there are multiple unserialized concurrent users of the
* same timer, then mod_timer() is the only safe way to modify the timeout,
* since add_timer() cannot modify an already running timer.
*
* The function returns whether it has modified a pending timer or not.
* (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
* active timer returns 1.)
*/
int mod_timer(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, 0);
}
EXPORT_SYMBOL(mod_timer);

15.7 del_timer 删除定时器

功能:删除定时器。

函数原型:

/**
* del_timer - deactivate a timer.
* @timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
*
* The function returns whether it has deactivated a pending timer or not.
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an
* active timer returns 1.)
*/
int del_timer(struct timer_list *timer)
{
struct timer_base *base;
unsigned long flags;
int ret = 0; debug_assert_init(timer); if (timer_pending(timer)) {
base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true);
raw_spin_unlock_irqrestore(&base->lock, flags);
} return ret;
}
EXPORT_SYMBOL(del_timer);

【linux】驱动-15-定时器的更多相关文章

  1. Linux驱动之定时器在按键去抖中的应用

    机械按键在按下的过程中会出现抖动的情况,如下图,这样就会导致本来按下一次按键的过程会出现多次中断,导致判断出错.在按键驱动程序中我们可以这么做: 在按键驱动程序中我们可以这么做来取消按键抖动的影响:当 ...

  2. linux驱动之定时器的介绍和内核时间的学习

    本文章摘自下面的网友: http://blog.sina.com.cn/s/blog_6e5b342e0100m87d.html 一.内核中如何记录时间 任何程序都需要时间控制,其主要目的是: 测量时 ...

  3. linux驱动之定时器的使用

    被文章摘自一下几位网友.非常感谢他们. http://blog.sina.com.cn/s/blog_57330c3401011cq3.html Linux的内核中定义了一个定时器的结构: #incl ...

  4. Linux驱动设计—— 中断与时钟

    中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...

  5. Linux驱动之触摸屏程序编写

    本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 ...

  6. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  7. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  8. linux驱动面试题整理

    1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也 ...

  9. Linux驱动面试题

    1. Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备. 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种 ...

  10. 编写linux驱动所用到的头文件(转)

    转自:http://blog.csdn.net/lufeiop02/article/details/6448497 关于linux驱动(应用)程序头文件使用 收藏 驱动程序: #include < ...

随机推荐

  1. lombok,Invalid byte tag in constant pool: 19

    今天偶到一个奇怪的问题: 三台生产服务器部署同样的代码,同样的tomcat ,jdk等环境. 其中有一台服务器启动时报lombok-1.18.6.jar!   Invalid byte tag in ...

  2. maven简单入门

    maven简单部署webapp项目流程及注意事项 maven了解 简介: Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM: Project Object Model),一组标准集合 ...

  3. 爬虫:获取动态加载数据(selenium)(某站)

    如果网站数据是动态加载,需要不停往下拉进度条才能显示数据,用selenium模拟浏览器下拉进度条可以实现动态数据的抓取. 本文希望找到某乎某话题下讨论较多的问题,以此再寻找每一问题涉及的话题关键词(侵 ...

  4. opencv——轮廓发现与轮廓(二值图像)分析

    引言 二值图像分析最常见的一个主要方式就是轮廓发现与轮廓分析,其中轮廓发现的目的是为轮廓分析做准备,经过轮廓分析我们可以得到轮廓各种有用的属性信息. 这里顺带提下边缘检测,和轮廓提取的区别: 边缘检测 ...

  5. 马哥Linux--elasticsearch

    ELK stack: Lucene: 文档:document 包含了一个或多个域的容器 field:value 域: 有很多选项 索引选项,存储选项,域向量使用选项 索引选项用于通过倒排索引来控制文本 ...

  6. jolokia配置Java监控

    wget http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-jvm/1.3.6/jolokia-jvm-1.3.6- ...

  7. 037.Python的UDP语法

    UDP语法 1 创建一个socket的UDP对象 import socket #创建对象 socket.SOCK_DGRAM 代表UDP协议 sk = socket.socket(type=socke ...

  8. linux服务之FTP服务篇

    一.FTP协议 FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务. FTP (File Transfer ...

  9. STM32F4-IAP学习笔记--(转)

    花了断断续续两天时间在STM32上面写了一个IAP(In Application Programing)Boot,期间多多少少还是遇到的了不少问题.现在就花点时间把这两天写的东西整理一下,就当是学习笔 ...

  10. 如何做好FAE工作及FAE职位发展————资深FAE总结推荐

    http://bbs.elecfans.com/jishu_932585_1_1.html 曾经认识一位做电源研发的工程师,转行在一家代理商做FAE,做了一年半以后,就提出了离职请求,他老板问他是什么 ...