当前位置:网站首页>内核中时间相关的知识介绍
内核中时间相关的知识介绍
2022-07-04 15:58:00 【正在起飞的蜗牛】
1、内核要解决的时间相关问题
(1)如何度量时间差,如何比较时间;
(2)如何获取当前时间;
(3)如何将操作延迟指定的一段时间;
(4)如何调度异步函数到指定的时间之后执行;
2、度量时间差
2.1、内核度量时间的原理
(1)Soc有时间相关的硬件,比如定时器、RTC等,其中就有计数器,就是每隔一段时间计数器的值就加一。计数器的值保存在
寄存器中,内核可以通过读取寄存器知道计数器的值;
(2)计数器的值增加的周期长短是可以计算得到的,和时钟频率有关。比如时钟频率是1000hz,则每1ms计数器的值加一。
(3)知道计数器的值和计数器值增加的时间间隔,就可以计算经过了多长的时间。比如计数器的值增加了1000,则经过的时间就是1000*1ms=1s;
(4)Soc自带的时钟模块可能计算不够精确,有时候需要外接时钟芯片;
参考博客:《ARM芯片开发(S5PV210芯片)——定时器、看门狗、RTC》;
2.2、内核的宏定义:HZ
(1)系统时钟中断由系统定时硬件以周期性的间隔产生,这个间隔在内核中就是根据HZ的值来指定;
(2)HZ在内核中是个宏定义,表示内核中每秒发生多少次时钟中断,HZ的值和平台有关;
(3)假设HZ的值是100,则表示每10ms内核的计数器的值就加一;
(4)一般是不修改HZ值,内核开发中已经为我们选择了合适的HZ值,我们只需要使用HZ值;理论上HZ的值越大,计数器增加的周期就越短,我们就能获取更准确的时间,但是增加时钟中断频率会带来额外的开销,需要在二者中取平衡。
2.3、jiffies计数器
(1)内核中有两个计数器jiffies和jiffies_64。jiffies_64是64位的(即使在32位架构上也是64位),jiffies是unsigned long型变量,在64位架构中是64位,在32位架构中是32位。64位架构中,jiffies和jiffies_64相同,在32位架构中,jiffies是jiffies_64的低32位;
(2)通常首选使用jiffies,因为对jiffies的访问很快;
(3)jiffies的值在系统启动时被初始化为0,每次当时钟中断发生时,jiffies计数器的值就加一。所以jiffies计数器的值表示自系统启动以来,发生了多少次时钟中断。
2.4、HZ和jiffies计数器的关系
(1)HZ表示每秒发生多少次时钟中断,jiffies记录了系统启动后发生的中断次数;
(2)系统启动经过的时间=jiffies / HZ;
(3)计算时间差=(jiffies1-jiffies2) / HZ;
2.5、比较两个jiffies值的函数
int time_after(unsigned long jiffies1, unsigned long jiffies2); //jiffies1代表的时间比jiffies2靠后,则返回真
int time_before(unsigned long jiffies1, unsigned long jiffies2); //jiffies1代表的时间比jiffies2靠前,则返回真
int time_after_eq(unsigned long jiffies1, unsigned long jiffies2); //jiffies1代表的时间比jiffies2靠后或相等,则返回真
int time_before_eq(unsigned long jiffies1, unsigned long jiffies2); //jiffies1代表的时间比jiffies2靠前或相等,则返回真
2.6、处理器特定寄存器
(1)有时候需要特别高的时间精度,有的处理器在硬件上做了针对性的设计,提供专门的时间计数器寄存器,这是和具体处理器关联的,没有通用性;
(2)比如:在X86架构的处理器中就有TSC(timestamp counter,时间戳计数器)寄存器,是一个64位的寄存器,记录CPU时钟周期数;
2.7、jiffies和struct timespes、struct timeval结构体转换函数
unsigned long timeval_to_jiffies(const struct timeval *value);
void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value);
unsigned long timespec_to_jiffies(const struct timespec *value);
void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);
3、获取当前时间
//获取系统当前时间
do_gettimeofday(struct timeval * tv);
//将墙钟时间转换为jiffies
static inline unsigned long mktime(const unsigned int year,
const unsigned int mon, const unsigned int day,
const unsigned int hour, const unsigned int min,
const unsigned int sec);
(1)墙钟时间:指日常生活使用的时间,用年月日时分秒来表达;
(2)在驱动程序中,一般是不需要墙钟时间的,大部分都是计算时间差,在上层应用中墙钟时间用的较多;
(3)内核中提供了获取当前时间戳的函数:do_gettimeofday()函数,用法和C库的gettimeofday是一样的;
(4)内核还提供了墙钟时间转换为jiffies的函数;
4、延时操作
4.1、延时操作思路介绍
(1)设备驱动程序中经常需要将某些特定代码延迟一段时间后执行,比如操作a需要等到操作b执行完成;
(2)实现延时操作有两种思路:忙等待和让出处理器;
(3)忙等待:在延时的这段时间内仍然占据CPU,直到满足延迟的时间,这种适合短延时,比较切换进程也是要开销的;
(4)让出处理器:在延时时间内让出处理器,等延迟时间到了再被调度,适合长延时;
4.2、等待队列
参考博客:《进程的休眠与唤醒(等待队列)》;
4.3、短延时——忙等待
//延时函数,三个延迟函数都是忙等待函数,因而在延迟过程中无法运行其他任务
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
4.4、短延时——让出处理器
//延时msecs毫秒
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs)
//延时seconds秒
void ssleep(unsigned int seconds)
5、内核定时器
5.1、定时器介绍
(1)我们需要在某个时间点调度执行某个动作,同时在该时间点到达之前不会阻塞当前进程,则可以使用内核定时器;内核定时器是利用中断来实现的,在到达指定时间点后发生中断,执行注册的函数;
(2)定时器的管理必须尽可能做到轻量级;
(3)其设计必须在活动定时器大量增加时具有很好的伸缩性;
(4)大部分定时器会在最多几秒或者几分钟内到期,而很少存在长期延迟的定时器;
(5)定时器应该在注册它的同一CPU上运行;
5.2、struct timer_list结构体
struct timer_list {
struct hlist_node entry;
unsigned long expires; //预期定时器执行的jiffies值
void (*function)(unsigned long); //绑定的执行函数
unsigned long data; //传给执行函数的参数
u32 flags;
};
struct timer_list结构体在内核中描述定时器,在到达expires指定的jiffies值时,执行function函数,并把data作为传参传给function函数;
5.3、定时器工作的逻辑流程
(1)构建定时器:初始化struct timer_list结构体,绑定执行函数、传参,设置定时的时间,有专门的初始化函数;
(2)将构建好的定时器向内核注册;
(3)到达设置的定时时间,调用注册函数;
(4)在注册函数中再次向内核注册该定时器;
(5)定时器重新开始计时,相当于从第二步开始循环执行;
5.4、示例代码
/* 实现每隔一秒向内核log中打印一条信息 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/timer.h>
static struct timer_list tm;
struct timeval oldtv;
void callback(unsigned long arg)
{
struct timeval tv;
char *strp = (char*)arg;
printk("%s: %lu, %s\n", __func__, jiffies, strp);
do_gettimeofday(&tv);
printk("%s: %ld, %ld\n", __func__,
tv.tv_sec - oldtv.tv_sec, //与上次中断间隔 s
tv.tv_usec- oldtv.tv_usec); //与上次中断间隔 ms
oldtv = tv;
tm.expires = jiffies+1*HZ;
add_timer(&tm); //再次注册定时器,重新开始计时
}
static int __init demo_init(void)
{
printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
init_timer(&tm); //初始化内核定时器
do_gettimeofday(&oldtv); //获取当前时间
tm.function= callback; //指定定时时间到后的回调函数
tm.data = (unsigned long)"hello world"; //回调函数的参数
tm.expires = jiffies+1*HZ; //定时时间为1s
add_timer(&tm); //注册定时器
return 0;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
del_timer(&tm); //注销定时器
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("yikoupeng");
MODULE_DESCRIPTION("timerlist");
上面的代码摘抄自《一口linux》;
tasklet机制和工作队列
边栏推荐
- 利用win10计划任务程序定时自动运行jar包
- Dynamic programming stock problem comparison
- Firewall basic transparent mode deployment and dual machine hot standby
- How to choose one plus 10 pro and iPhone 13?
- R语言plotly可视化:plotly可视化互相重叠的直方图(historgram)、并在直方图的顶部边缘使用geom_rug函数添加边缘轴须图Marginal rug plots
- kaili不能输入中文怎么办???
- What grade does Anxin securities belong to? Is it safe to open an account
- What is low code development?
- How to implement a delay queue?
- 【Unity UGUI】ScrollRect 动态缩放格子大小,自动定位到中间的格子
猜你喜欢
Hidden corners of coder Edition: five things that developers hate most
Datakit -- the real unified observability agent
超标量处理器设计 姚永斌 第7章 寄存器重命名 摘录
电子宠物小狗-内部结构是什么?
How to choose one plus 10 pro and iPhone 13?
What if Kaili can't input Chinese???
Master the use of auto analyze in data warehouse
RecastNavigation 之 Recast
With an annual income of more than 8 million, he has five full-time jobs. He still has time to play games
Ks007 realizes personal blog system based on JSP
随机推荐
防火墙基础透明模式部署和双机热备
gatling 之性能测试
Summary of tx.origin security issues
The test experience "tortured" by the PMP test is worth your review
设置窗体透明 隐藏任务栏 与全屏显示
Solution of commercial supply chain coordination system in the mineral industry: build a digital intelligent supply chain platform to ensure the safe supply of mineral resources
新享科技发布小程序UniPro小优 满足客户移动办公场景
About the pit of firewall opening 8848 when Nacos is started
To sort out messy header files, I use include what you use
上网成瘾改变大脑结构:语言功能受影响,让人话都说不利索
7 RSA密码体制
Spark 中的 Rebalance 操作以及与Repartition操作的区别
To sort out messy header files, I use include what you use
Datakit -- the real unified observability agent
TP configuring multiple databases
安信证券手机版下载 网上开户安全吗
什么是低代码开发?
Redis 的内存淘汰策略和过期删除策略的区别
金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
开发者,MySQL专栏完更,助你轻松从安装到入门进阶