深入理解Linux内核 学习笔记(5)
第五章 定时测量
内核必须显式地与三种时钟打交道:实时时钟(Real Time Clock, RTC)、时间标记计数器(Time Stamp Counter, TSC)及可编程间隔定时器( ProgrammableIntervalTimer,PIT)。前两种硬件设备允许内核跟踪当前的时间;后一种设备由内核编程,以使它能以固定的、预先定义的频率发出中断。对于内核和用户程序使用的定时器来说,这样的周期性巾断是至关重要的。
实时时钟:
所有的PC都包含了一个叫实时时钟(RTC)的时钟.它是独立于CPU和所有其他芯片的。即使当PC关掉电源,RTC还继续走,因为它靠个小电池或蓄电池供电。RTC能发出周期性的中断,可作为一个闹钟来工作。
Linux只用RTC来获得时间和日期,然而,通过作用于/dev/rtc设备文件,也允许进程对RTC编程。内核通过0x70和0x71 1/O端口存取RTC。通过执行/sbin/clock系统程序(它直接作用于这两个I/O端口),系统管理员可以配置时钟。
时间标记计数器
一个64位的时间标记计数器(TSC)的寄存器,可以通过汇编语言指令rdtsc读这个寄存器。这个寄存器是一个计数器,它在每个时钟信号到来时加1,例如,如果时钟节拍的频率是400 MHz,那么,时间标记计数器每2.5纳秒增加一次。Linux 利用这个寄存器获得精准的时间测量
可编程间隔定时器
时间测量设备,到了发定时中断,PLT以某一固定的频率(由内核决定)不停地发出中断,定时中断的间隔叫做节拍,
时间计数器TSC :
如果CPU有TSC寄存器,用do_ gett imeofday()计算当前时间,否则,用
do_ normal_ gettime()计算。 在do_ _get_ fast_ time变量存放的指针指向合适的函数。
当TSC寄存器可用时,用do_ fast_ gett imecffset ()计算微秒数,否则,用do_ slow_ gect imeof fset ()计算。这个函数的地址存放在do_ gett imeoffset变量中。
在内核启动时运行的time_ init() 函数能将这些变最指向正确的函数。
进程描述符的counter域表示进程在CPU上运行剩余节拍数。(counter由一个下半部分以延缓的方式更新,一次递减可能大于一个节拍),变得小于0时,把need_resched置为1,恢复用户态程序执行时掉schedule,换程序在CPU执行
系统调用函数adjtimex(),每660s调用set_rtc_mmss调整一次实时时钟。
定时器:
一种软件工具,每个定时器有一个域,表示需要多长时间到期,jiffies+正确节拍数,每次内核检查定时器,就用jiffies和这个比较。由于使用下半部分,所以不能严格遵守时间(延迟几百ms)
Linux有三种类型的定时器,静态定时器,动态定时器和间隔定时器,前两者有内核使用,第三种可以由进程在用户态创建。
静态定时器
存在timer_table数组,每项一个结构体,
|
struct t imer_ struct ( void (*fr.) lvoid) ; |
expires域指定定时器到期时间。这个时间被表示成自系统启动以来的时钟节拍数。expires值小于或等于jiffies值的所有定时器就认为是到期了或停止了。fn域包含定时器到期时被执行函数的地址。
静态定时器检测工作也是由TIMER_BH下半部分调用函数检查。在内核激活一个定时器时,要在timer_active设置合适的 标志,这里会先清0然后执行fn。
动态定时器
|
struct timer_ struct timer_ struct tiner_ unsigned long uns igned long void (* funct };. |
function域包含定时器到期时要执行函数的地址。data域指定传递给这个定时器函数的参数。
data域使得定义一个通用闲数处理几个设备驱动程序的定时问题成为可能,可以在data域存放设备ID,或其他有意义的数据,这些数据可被用来区分不同设备的函数使用。
expires域的含义与静态定时器相应域的含义相同。,
next和prev域实现双向循环链表的连接。事实上,每个活动动态定时器根据expires的值被精确地插人到512个双向循环链表的其中-一个中。在本章稍后将描述使用这个链表的算法。
动态定时器的遍历不像静态的是单循环,使用了一个聪明的数据结构。这个数据结构叫tvecs的数组,数组的元素指向tv1-5结构标识的链表。tv1是struct timer_vec_root,
|
struct timer_vec_root ( |
其TVR_SIZE为256,index指定当前扫描的链表,每个节拍时增1,模256为0时,由tv2-tv5顺序补充。每个vec指向一个timer_ list链表。
tv2-tv4这个TVR_SIZE为64,炎型为struct timer_vec的tv2、tv3及tv4結枸分別包含了在緊接着到来的214-1、220-1及226-1个节拍内將要到期的所有动态定吋器。
tv5的结构与前面的几个结构相同,除了vec数组的最后一项包含的动态定时器expires域的值可以任意大,它再也不需要从另一个数组进行补充了。
动态定时器的应用:在一些情况下,例如,当内核不能提供一个给定的服务时,就可以把当前进程挂起一个固定的时间。这通常是通过执行一个进程延时完成的。
与定时测量相关的系统调用:
Gettimeofday():该函数实现了time()和ftime(),root用户可以调用stime或settimeofday来修改当前日期和时间,不过请注意当这两个系统调用修改xtime的值时都没有修改RTC寄存器,因此当系统关机时新的时间会丢失,除非用户执行/sbin/clock这个程序来改变RTC的值。
Settimer和alarm:间隔定时器,
通过POSIX setit imer ()系统调用可以激活间隔定时器。第一个参数指定应当采取下面的哪一个策略:
ITIMER_REAL:真正过去的时间;进程接受SIGALRM信号
ITIMER_VIRTUAL:进程在用户念下花费的时间;进程接受SIGVTALRM信号
ITIMER_PROF:进程既在用户态下又在内核态下所花费的时间;进程接受SIGPROF信号
为了能分别实现前述每种策略的间隔定时器,进程描述符要包含三对域:
it_real_incr 和it_real_value
it_virt_incr 和it_virt_value
it_prof_incr 和it_prof_value
每对中的第一个域存放着两个信号之间以节拍为单位的问隔;另一个城存放着定时器的当前值。
ITIMER_REAL间隔定时器是利用动态定时器实现的,因为即使进程不在CPU上运行时,内核也必须向进程发送信号。因此,每个进程描述符包含一个叫real_ timer的动态定时器对象。setitimer(}系统调用初始化rea1_timer域,然后调用add_timer()把动态定时器插人到合适的链表中。当定时器到期时,内核执行it_rea1_fn()定时函数。依次类推,it_real_in() 函数向进程发送一个SIGALRM信号。如果it_real_incr不为空,那么它会再次设置expires城,重新激活定时器。
ITIMER_VIRTUAL和ITIMER_PROF间隔定时器不需要动态定时器,因为只有当进程运行时,它们才能被更新: do_it_virt()和dc_it_prof () 由update_ore_process ()调用,当执行TIMER_BH下半部分时update_one_process()才运行。因此,每个节拍中,这两个间隔定时器通常都被更新--次,并且如果它们到期,就给当前进程发送一个合适的信号。
a1arm()系统调用会在一个指定的时间间隔用完时向调用的进程发送一个SIGALRM信号。当以ITIMER_ REAL为参数调用时,它非常类似于setitimer(),因为它利用了包含在进程描述符中的real_timer动态定时器。因此,不能同时使用以ITIMER_REAL为参数的alarm()和setitimer()。
深入理解Linux内核 学习笔记(5)的更多相关文章
- 深入理解Linux内核 学习笔记(1)
1.用户和用户组 每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识.每个文件的相关权限也恰好与一个组相对应. root为超级用户, 2.模块 为了达到微内 ...
- 深入理解Linux内核 学习笔记(4)
第四章 中断和异常 中断通常被分为同步中断和异步中断,同步中断是当指令执行时由CPU控制单元产生的,之所以称为同步,是因为只有在一条指令终止执行后CPU才会发出中断异步中断是由其他硬件设备依照CPU时 ...
- 深入理解Linux内核 学习笔记(3)
第三章 进程 可以看到很多熟悉的结构体 进程状态: 可运行状态(TASK_ RUNNING) 进程要么在CPU上执行,要么准备执行. 可巾断的等待状态(TASK_ INTERRUPTIBLE) 进程被 ...
- 深入理解Linux内核 学习笔记(2)
第二章 :内存寻址 略.基本同计算机组成原理中的讲述 内核代码和数据结构会存储在一个保留的页框中. 常规Linux安装在RAM物理地址0x00100000开始的地方.因为:页框0是由BIOS使用,存放 ...
- 深入理解Linux内核 学习笔记(8)
第八章 系统调用 API定义了一个给定的服务:系统调用是通过软中断向内核发出一个明确的请求. API可能不调用系统调用,也可能调用多个系统调用. Linux系统调用必须通过执行int 0x80,系统调 ...
- 20135316王剑桥Linux内核学习笔记
王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记二——进程
Linux内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
随机推荐
- [Java算法分析与设计]--线性结构与顺序表(List)的实现应用
说到线性结构,我们应该立马能够在脑子里蹦出"Array数组"这个词.在Java当中,数组和对象区别基本数据类型存放在堆当中.它是一连串同类型数据存放的一个整体.通常我们定义的方式为 ...
- java面试总结
一.java的集合框架 HashMap.HashTable.CurrentHashMap的底层数据结构与区别? CurrentHashMap与HashTable是如何保证线程安全的? ArrayLis ...
- 1、学习笔记之——html
这篇学习笔记是在看一些教学视频学习时所记,可能比较乱,就当是自己以后复习的资料好了. <!doctype html> <html> <head> <meta ...
- MySql常用两大存储引擎简介
MyISAM存储引擎简介 MyISAM存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件. 首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm文件,另外还有.MYD和.M ...
- Oracle-02:SQL语言的分类或者说SQL语言的组成
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 小结一版: 01.DDL(Data Definition Language)数据定义语言. 用来创建数据库中 ...
- 在Ubuntu16.04上配置.Net Core 2 环境
一.安装.Net Core SDK 按照官方文档,执行以下命令安装SDK curl https://packages.microsoft.com/keys/microsoft.asc | gpg -- ...
- Nodejs.调用Linux命令
当需要Node.js在后台帮忙运行Linux命令脚本时, 可以用上以下方法 上代码 var spawn = require('child_process').spawn; free = spawn(' ...
- go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go
从本节开始,将逐步阅读nsq各模块的代码. 读一份代码,我的思路一般是: 1.了解用法,知道了怎么使用,对理解代码有宏观上有很大帮助. 2.了解各大模块的功能特点,同时再想想,如果让自己来实现这些模块 ...
- Nordic nRF51/nRF52开发流程说明
Nordic nRF51系列包括nRF51822/nRF51422/nRF51802等芯片,nRF52系列包括nRF52832/nRF52840/nRF52810等芯片,硬件工程师可以按照如下流程去评 ...
- bzoj 1098 poi2007 办公楼 bfs+链表
题意很好理解,求给出图反图的联通块个数. 考虑这样一个事情:一个联通块里的点,最多只会被遍历一次,再遍历时没有任何意义 所以用链表来存,每遍历到一个点就将该点删掉 #include<cstdio ...