深入理解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内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
随机推荐
- C#本质论笔记
第一章 C#概述 1.1 Helo,World 学习一种新语言最好的办法就是动手写程序. C#编译器创建的.exe程序是一个程序集(Assembly),我们也可以创建能由另一个较大的程序 ...
- Python_json
import json ''' Python内置了json包来帮助我们完成对json的操作. 将Python的字典结构导出到json使用json.dumps(),将json读成Python的字典结构, ...
- OC和Swift中的UITabBar和UINaviGationBar的适配 [UITabbar在IPad中的适配]
作者 sundays http://www.cnblogs.com/sundaysgarden/ OC中UITabbar的适配[iphoneX和Ipad适配] 自定可以UITabar 自定义UITab ...
- js基础进阶--编的实用技巧(一)
我的个人博客:http://www.xiaolongwu.cn 在平时的开发中,编码技巧很重要,会让你少写很多代码,起到事倍功半的效果. 下面总结几种简单的技巧,大家共同学习一下 1. 利用+.-./ ...
- PAT1126:Eulerian Path
1126. Eulerian Path (25) 时间限制 300 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue In grap ...
- JSP中的隐含对象
什么是JSP中隐含对象:容器自动创建,在JSP文件中可以直接使用的对象. 作用:JSP预先创建的这些对象可以简化对HTTP的请求,响应信息的访问. JSP中的隐含对象: 输入输出对象:request. ...
- Java NIO核心组件简介
原文链接:http://tutorials.jenkov.com/java-nio/overview.html NIO包含下面几个核心的组件: Channels Buffer Selector 整个N ...
- SSM-SpringMVC-20:SpringMVC中处理器方法之返回值void篇
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 处理器的方法我们之前做过,返回值为String的,返回值为ModelAndView的,我们这个讲的这个返回 ...
- Linux时间子系统之(五):POSIX Clock
专题文档汇总目录 Notes: 本章主要介绍了若干种类的静态时钟,这些时钟都可以通过k_clock表示,注册到posix_clocks中.这些都是静态时钟,可以分为三大类:各种REALTIME时钟.带 ...
- C3垂直居中均分
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...