Linux内核设计与实现(11)第十一章:定时器和时间管理

1. 内核对时间的使用概述:

内核中有大量的函数都是基于时间驱动的,其中有一些是周期执行的,比如对调度程序中的运行队列进行平衡调整、刷新屏幕、检测当前进程是否用尽了自己的时间片等。
另一些则需要等待一个相对时间后才运行,比如要推后执行的IO操作等。除了这两种情况,内核还必须管理系统的运行时间以及当前时间。

2. 系统时间

系统中管理的时间有2种:实际时间和定时器

2.1 实际时间

实际时间的获取是在开机后,内核初始化时从RTC(实时时钟的缩写)读取的。
内核读取这个时间后就将其放入内核中的 xtime 变量中,并且在系统的运行中不断更新这个值。

当前实际时间(墙上时间)定义为struct timespec xtime;
结构体timespec中有一个long域tv_sec以秒为单位,存放着自1970年1月1日以来经过的时间。
此外还有一个v_nsec域记录自上一秒开始经过的ns数。读取xtime变量需要使用xtime_lock锁,该锁不是普通自旋锁,而是一个seqlock锁。

struct timespec 有两个成员,一个是秒,一个是纳秒, 所以最高精确度是纳秒.

struct timespec
{
	time_t tv_sec; /* seconds */	//存放着自1970年1月1日以来经过的时间
	long tv_nsec; /* nanoseconds */  //纳秒
};

其他时间相关结构体参考:
linux 时间 time(1)-时间相关结构体和函数详解
https://blog.csdn.net/lqy971966/article/details/107975594

2.2 定时器

内核中的定时器有2种,静态定时器和动态定时器。

2.2.1 静态定时器

静态定时器一般执行了一些周期性的固定工作:

更新系统运行时间,
更新实际时间,
时间片等,
更新资源消耗和处理器时间统计值

2.2.2 动态定时器

动态定时器顾名思义,是在需要时(一般是推迟程序执行)动态创建的定时器,使用后销毁(一般都是只用一次)。
一般我们在内核代码中使用的定时器基本都是动态定时器
定时器是内核中主要使用的时间管理方法,通过定时器,可以有效的调度程序的执行。

3. 基础概念大搜罗:HZ,节拍,jiffies,定时器中断,实时时钟

3.1 HZ 赫兹

HZ:单位时间内完成振动或振荡的次数或周数。

LINUX 系统时钟频率是一个常数HZ来决定的,通常HZ=100,那么他的精度度就是10ms(毫秒)。
也就是说每10ms一次中断。所以一般来说Linux的精确度是10毫秒

3.2 节拍(tick)

连续两次时钟中断的时间间隔就称为节拍(tick)。

3.3 jiffies

简单说就是:电脑开机到现在总共的时钟中断次数

计算:

记录自系统启动以来产生的总节拍数,比如系统启动了 N 秒,那么 jiffies就为 N×HZ

初始化:

系统启动时内核将该变量初始化为0,此后每次时钟中断处理程序会增加该变量的值;
一秒内增加的值即HZ,系统运行时间以秒为单位计算就等于jiffies/HZ。

使用定时器时一般都是以jiffies为单位来延迟程序执行的,比如延迟5个节拍后执行的话,执行时间就是 jiffies+5。

3.3.1 jiffies常用的一些运算

unsigned long time_stamp = jiffies;	/* 现在 */ 
unsigned long next_tick = jiffies+1;	/* 从现在开始的下一个节拍 */ 
unsigned long later = jiffies + 5*HZ;	/* 从现在开始后的5秒 */ 
unsigned long fraction = jiffies + HZ/10;	/* 从现在开始后的100ms,就是0.1秒,也就是0.1*HZ */

3.3.2 回绕问题

因为jiffies使用unsigned long,所以在32位机器上(最大值为 2^32-1),时钟频率为100HZ的情况下,497天后会溢出,如果频率为1000HZ,49.7天后就会溢出。
溢出后其值会绕回到0。内核中提供了四个宏用来帮助比较节拍计数,它们能正确地处理节拍计数回绕的情况。

解决回绕……麻烦

include/linux/jiffies.h

3.4 定时器中断:

周期性产生的事件都是由系统定时器驱动的,系统定时器是一种可编程的硬件芯片,它能以固定频率产生中断·,该中断就是所谓的定时器中断。
它所对应的中断处理程序负责更新系统时间,也负责执行需要周期性运行的任务。

3.5 实时时钟

除了系统定时器,体系结构还提供了另一种计时设备,即实时时钟。
实时时钟是用来持久存放系统时间的设备,即便系统关闭后,它也可以靠主板上的微型电池提供的电力保持系统的计时。
实时时钟最主要的作用是在系统启动时初始化xtime变量(墙上时间,象征真实的用户时间)。

4. 定时器执行流程

定时器在内核中用一个链表来保存的,链表的每个节点都是一个定时器。
定时器的生命周期:

初始化-填充-激活/修改-触发-删除

4.1 伪代码实例

	//实例
	struct timer_list my_timer;
	init_timer(&my_timer);	//初始化
	
	my_timer.expires = jiffies + delay;	//填充定时器 注意单位是节拍
	my_timer.data = 0;
	my_timer.function = my_function;
	
	add_timer(&my_timer);	//激活定时器
	
	mod_timer(&my_timer,jiffies+new_delay); //修改定时器
	
	del_timer(&my_timer);  //删除,为了避免竞争条件,建议使用 del_timer_sync 函数来删除定时器

5. 实现程序延迟的方法 schedule_timeout

这个函数会将当前的任务睡眠到指定时间后唤醒,所以等待时不会占用CPU时间。

/* 将任务设置为可中断睡眠状态 */
set_current_state(TASK_INTERRUPTIBLE);
/* 小睡一会儿,“s“秒后唤醒 */
schedule_timeout(s*HZ);

schedule_timeout 一般用于延迟时间较长的程序。也就是延迟大于 1 个节拍(jiffies)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值