Linux内核定时器--原版PPT优秀课件
定时器(共12张PPT)优秀
是fo的稳定性极好。
2.施密特触发器和单稳态触发器,虽然不能自动地产生矩形脉冲,但 却可以把其它形状的信号变换成为矩形波,为数字系统提供标准的 脉冲信号。
定时器是一种用途很广的集成电路,除了能组成施密特触发器、单稳态触 发器和多谐振荡器以外,还可以接成各种灵活多变的应用电路。
4.除了555定时器外,还有556(双定时器)和558(四定时器)等。
(3)2脚为触发输入端,6脚为阈值输入端,两端的电位高低控制比较器C1和C2的输出,从而控制RS触发器,决定输出状态。
(2)恢复时间t (2)5脚为电压控制端,当其悬空时,比较器C1和C2的比较电压分别为2/3VCC 和1/3VCC 。
T2R2C
VT—=1 /3VCC。
re
多谐振荡器是一种自激振荡电路,不需要外加输入信号,就可以自动地产生出矩形脉冲。
4 用555定时器构成的多谐振荡器 正常工作时,应将其接高电平。 占空比可调的多谐振荡器电路
ห้องสมุดไป่ตู้
tre=(3~5)τ2
(3)最高工作频率f (3)2脚为触发输入端,6脚为阈值输入端,两端的电位高低控制比较器C1和C2的输出,从而控制RS触发器,决定输出状态。
3 用555定时器组成单稳态触发器 tre=(3~5)τ2
第九页,共12页。
2. 振荡频率的估算
(1)电容充电时间T1:(用三要素法计算)
T1 1lnvvCC(( ))vvCC((0T1))
VCC 1 ln
VCC
1 3
V
CC
2 3
V
CC
0.7(R1R2)C
(2) 电容放电时间T2
T2 0.7R2C
(3)电路振荡周期T
LINUX内核进程管理PPT幻灯片
❖ suid和sgid是根据POSIX标准引入的,在系统调用改变uid 和gid时,用于保留真正的uid和gid。
❖ fsuid和fsgid称为文件系统的uid和gid,用于对文件系统操
作时的合法性检查,是LINUX独特的标识类型。它们一般分
别和euid和egid一致,但在NFS文件系统中NFS服务器需要
SIGSTP、SIGTTIN 或SIGTTOU)的反应; 其二是受到父进程ptrace调用的控制,
而暂时将处理机交给控制进程。
35
◆ ZOMBIE: 僵尸状态。 表示进程结束但尚未消亡的一种状态。 此时进程已经结束运行并释放大部分资
源,但尚未释放进程控制块。
36
进程调度
调度程序(scheduler)用来实现进程状态 之间的转换。
0 1 //等待资源 2 4 //等待信号 8
29
◆ RUNNING: 正在运行,或者在就绪队列中等待运行
的进程。 也就是上面提到的运行态和就绪态进程
的综合。 一个进程处于RUNNING状态,并不代表
它一定在被执行。
31
由于在多任务系统中,各个就绪进程需 要并发执行,所以在某个特定时刻,这些处 于RUNNING状态的进程之中,只有一个能 够得到处理机,而其他进程必须在一个就绪 队列中等待。
4
2. 动态性
进程与程序的区别在于,程序只是一个静态的 指令集合,而进程是一个正在系统中活动的指令集 合。
在进程中加入了时间的概念。进程具有自己的 生命周期和各种不同的状态,这些概念在程序中都 是不具备的。
5
由于以上两个性质,又可以衍生出进程 的第三个重要特性,即并发性。
若干个进程可以在单处理机状态上并发 执行。注意并发性(concurrency)和多处理机 并行(parallel)是两个不同的概念。
Linux内核.ppt
❖ LINUX文件系统: Linux文件系统是文件存放在磁盘等存储设
备上的组织方法。Linux能支持多种目前浒的文件系统,如EXT2、EXT3、 FAT、VFAT、ISO9660、NFS、SMB等。
❖ LINUX应用系统:标准的Linux系统都有一整套称为应
用程序的程序集,包括文本编辑器、编程语言、X Window、 办公套件、Internet工具、数据库等。
❖GNU 软件和派生工作均适用 GNU 通用公共许 可证,即 GPL(General Public License )
❖Linux的开发使用了众多的GUN工具
<>
GPL-开源软件的法律
❖GPL 允许软件作者拥有软件版权 ❖但GPL规定授予其他任何人以合法复
制、发行和修改软件的权利。
<>
2. Linux系统的主要特点
内核模块的能力
所有模块全部运行在内核态,直接调用函数,无需消息传递 支持多称多处理SMP机制
讲究效率的单模块操作系统
进程管理
内存管理
设备管理
文件管理
模块之间可以互相调用的单模块结构 <>
讲究效率的单模块操作系统
❖模块之间直接调用函数,除了函数调用 的开销外,没有额外开销。 ❖庞大的操作系统有数以千计的函数 ❖复杂的调用关系势必导致操作系统维护 的困难
个平台使它仍然能按其自身的方式运行的能力。Linux是一种可 移植的操作系统,能够在从微型计算机到大型计算机的任何环境 中和任何平台上运行。
3. LINUX的组成
❖ LINUX的内核:内核是系统的核心,是运行程序和管理
像磁盘和打印机等硬件设备的核心程序。
❖ LINUX SHELL: Shell是系统的用户界面,提供了用户与内核进
linux内核定时器详解及实例
Linux内核定时器详解80X86体系结构上,常用的定时器电路实时时钟(RTC)RTC内核通过IRQ8上发出周期性的中断,频率在2-8192HZ之间,掉电后依然工作,内核通过访问0x70和0x71 I/O端口访问RTC。
时间戳计时器(TSC)利用CLK输入引线,接收外部振荡器的时钟信号,该计算器是利用64位的时间戳计时器寄存器来实现额,与可编程间隔定时器传递来的时间测量相比,更为精确。
可编程间隔定时器(PIT)PIT的作用类似于微波炉的闹钟,PIT永远以内核确定的固定频率发出中断,但频率不算高。
CPU本地定时器利用PIC或者APIC总线的时钟计算。
高精度时间定时器(HPET)功能比较强大,家机很少用,也不去记了。
ACPI电源管理定时器它的时钟信号拥有大约为3.58MHZ的固定频率,该设备实际上是一个简单的计数器,为了读取计算器的值,内核需要访问某个I/O端口,需要初始化定时器的数据结构利用timer_opts描述定时器Timer_opts的数据结构Name :标志定时器员的一个字符串Mark_offset :记录上一个节拍开始所经过的时间,由时钟中断处理程序调用Get_offset 返回自上一个节拍开始所经过的时间Monotonic_clock :返回自内核初始化开始所经过的纳秒数Delay:等待制定数目的“循环”定时插补就好像我们要为1小时35分34秒进行定时,我们不可能用秒表去统计,肯定先使用计算时的表,再用计算分的,最后才用秒表,在80x86架构的定时器也会使用各种定时器去进行定时插补,我们可以通过cur_timer指针来实现。
单处理器系统上的计时体系结构所有与定时有关的活动都是由IRQ线0上的可编程间隔定时器的中断触发。
初始化阶段1. 初始化间,time_init()函数被调用来建立计时体系结构2. 初始化xtime变量(xtime变量存放当前时间和日期,它是一个timespec 类型的数据结构)3. 初始化wall_to_monotonic变量,它跟xtime是同一类型的,但它存放将加在xtime上的描述和纳秒数,这样即使突发改变xtime也不会受到影响。
Linux教程第15章 内核时钟与定时器
第15章内核时钟与定时器实验目的●学习Linux系统中的时钟和定时器原理●分析理解Linux内核时间的实现机制●分析比较ITIMER_REAL、ITIMER_VIRTUAL、ITIMER_PROF●学习理解内核中各种定时器的实现机制●掌握操作定时器的命令,掌握定时器的使用实验内容针对一个计算fibonacci数的进程,设定三个定时器,获取该进程在用户模式的运行时间,在内核模式的运行时间,以及总的运行时间。
提示:setitimer()/getitimer()系统调用的使用。
ITIMER_REAL实时计数;ITIMER_VIRTUAL统计进程在用户模式(进程本身执行)执行的时间;ITIMER_PROF统计进程在用户模式(进程本身执行)和内核模式(系统代表进程执行)下的执行时间,与ITIMER_VIRTUAL比较,这个计时器记录的时间多了该进程内核模式执行过程中消耗的时间。
实验原理15.1 关于时钟和定时器一台装有操作系统的计算机里一般有两个时钟:硬件时钟和软件时钟。
硬件时钟从根本上讲是CMOS时钟,是由小型电池供电的时钟,这种电池一般可持续供电三年左右。
因为有自己的电池,所以当计算机断电的时候CMOS时钟可以继续运行,这就是为什么你的计算机总是知道正确的日期和时间的原因。
而软件时钟则是由操作系统本身维护的,所以又称系统时钟。
这个时钟是在系统启动时,读取硬件时钟获得的,而不是靠记忆计时。
在得到硬件时钟之后,就完全由系统本身维护。
之所以使用两套时钟的原因是因为硬件时钟的读取太麻烦,所消耗的时间太长。
硬件时钟的主要作用就是提供计时和产生精确时钟中断。
而软件时钟的作用则可以归纳为下面的几条:●保存正确时间。
●防止进程超额使用CPU。
●记录CPU的使用情况。
●处理用户进程发出的系统调用。
Linux内核定时器
二、作用:一个timer_list结构体的实例对应一个定时器,在linux设备驱动编程中,可以使用timer_list和基于它的一些操作(函数)来完成定时出发工作或者完成某周期性的事物。
三、个字段详解:1、struct list_head entry--定时器链表,用于存放软定时器,该链表根据定时器expirex 字段的值将它们分组存放。
2、unsigned long expires--定时器的到期时间,到达expires时间后,定时器将调用其成员函数function,其中将data字段作为function的参数。
该字段表示的时间是以时间节拍为单位。
例如如果你想定时一秒,则expires=jiffies+HZ*1。
A、关于jiffies的详解见我们知道,操作系统应该能够在将来某个时刻准时调度某个任务,所以需要一种能保证任务准时调度运行的机制。
希望支持每种操作系统的微处理器必须包含一个可周期性中断它的可编程间隔定时器。
这个周期性中断被称为系统时钟滴答(或system timer),它象节拍器一样来组织系统任务,也称为时钟中断。
时钟中断的发生频率设定为HZ,HZ是一个与体系结构无关的常数,在文件<linux/param.h>中定义,时钟中断对操作系统是非常重要的,当时钟中断发生时,将周期性地执行一些功能,例如:. 更新系统的uptime. 更新time of day. 检查当前任务的时间片是否用光,如果是则需要重新调度任务. 执行到期的dynamic timer. 更新系统资源使用统计和任务所用的时间统计3、void (*function)(unsigned long)--定时器处理函数,也就是说到达expires时间时,function函数将被调用执行。
其参数来自定时器的data字段。
4、unsigned long data--在调用function函数时,该字段作为其参数被使用。
四、操作:1、定义及初始化:struct timer_list timer;(1)-- void init_timer(struct timer_list *timer){debug_timer_init(timer);__init_timer(timer);}(4)--setup_timer(&timer);等同于定义方式(2)和(3),不过对base字段的赋值是调用了init_timer()函数。
linux定时器
定时器timer说明:/******************* linux内核的时间管理******************/(1)内核中的时间概念时间管理在linux内核中占有非常重要的作用。
相对于事件驱动而言,内核中有大量函数是基于时间驱动的。
有些函数是周期执行的,比如每10毫秒刷新一次屏幕;有些函数是推后一定时间执行的,比如内核在500毫秒后执行某项任务。
要区分:*绝对时间和相对时间*周期性产生的事件和推迟执行的事件周期性事件是由系统系统定时器驱动的(2)HZ值内核必须在硬件定时器的帮助下才能计算和管理时间。
定时器产生中断的频率称为节拍率(tick rate)。
在内核中指定了一个变量HZ,内核初始化的时候会根据这个值确定定时器的节拍率。
HZ定义在<asm/param.h>,在i386平台上,目前采用的HZ值是1000。
也就是时钟中断每秒发生1000次,周期为1毫秒。
即:#define HZ 1000注意!HZ不是个固定不变的值,它是可以更改的,可以在内核源代码配置的时候输入。
不同的体系结构其HZ值是不一样的,比如arm就采用100。
如果在驱动中要使用系统的中断频率,直接使用HZ,而不要用100或1000。
a.理想的HZ值i386的HZ值一直采用100,直到2.5版后才改为1000。
提高节拍率意味着时钟中断产生的更加频繁,中断处理程序也会更频繁地执行。
带来的好处有:*内核定时器能够以更高的频率和更高的准确度运行*依赖定时器执行的系统调用,比如poll()和select(),运行的精度更高*提高进程抢占的准确度(缩短了调度延时,如果进程还剩2ms时间片,在10ms的调度周期下,进程会多运行8ms。
由于耽误了抢占,对于一些对时间要求严格的任务会产生影响)坏处有:*节拍率越高,系统负担越重。
中断处理程序将占用更多的处理器时间。
(3)jiffies全局变量jiffies用于记录系统启动以来产生的节拍的总数。
Linux操作系统内核原理PPT课件
进程虚存空间 虚存区
虚存区
分页式内存管理
• Linux系统中使用了同时用于64位和32位系统 的通用分页模型。
• 模型中使用四级页表,32位系统只使用PGD和 PTE两项
线性地址 64位
页全局目录PGD 页上级目录PUD 页中级目录PMD 页表PTE
页内偏移
页框
cr3
第20页/共28页
Linux物理内存管理
• Linux内核为了适应不同的硬件架构,对不同性
能的内存分成不同的节点(Node),内存模型如下
图:
pg_data_t
内存节点 16M
ZONE_DMA
node_zones
zone
ZONE_NORMAL
896M
ZONE_DMA
ZONE_NORMAL ZONE_HIGHMEM
zone_mem_map
nopage swapin swaout
……
……
vm_area_struct vm_start vm_end …… vm_ops vm_next
vm_area_struct vm_start vm_end …… vm_ops vm_next
vm_area_struct vm_start vm_end …… vm_ops vm_next
进程1 进程2 进程3
进程n 用户态
…… ……
内核线程1
内核线程2
内核线程3
内 核
内核线程4
功 能
内核线程5
函
数
第3页/共28页
内核线程n
内核态 地址空间
进程和线程的区别
• 线程是系统最小的执行流单位,一个线程就是 一个执行过程,是任务调度的基本单位。
定时器PPT课件
D3 — 未定义。
D2~D0 — PS2~PS0位:定时器分频因子选择位(Timer Prescaler Select Bits)。这三位定义定时器的分频因子,记为:p,定 义如下:
PS2、PS1、PS0=000 001 010 011 100 101 110 111
p =1 2 4 8 16 32 64 未定义
3 .
(3)可编程计数器/定时器
利用专门的可编程计数器/定时器实现计数与定时,克服了完全硬 件方式与完全软件方式的缺点,设定之后与CPU并行地工作。应用可编 程计数器/定时器,在简单的软件控制下,可以产生准确的时间延时。 这种方法的主要思想是根据需要的定时时间,用指令对计数器/定时器 设置定时常数,并用指令启动计数器/定时器。这种方法最突出的优点 是计数时不占用CPU的时间,并且,如果利用计数器/定时器产生中断 信号就可以建立多作业的环境,所以,可大大提高CPU的利用率。
它是一个16位寄存器,分为高8位、低8位,地址分别为$0021、 $0022,它的作用是:当定时器的状态和控制寄存器的TSTOP位=0时, 即允许计数时,每一计数周期,其值自动加1,当它达到设定值(在16位预 置寄存器中)时,TOF=1,同时计数寄存器自动清0。
(3)T1预置寄存器(T1 Counter Modulo Register, T1MODH、T1MODL)
4 .
10.1.2 MC68HC908GP32 MCU的定时接口的基本 原理的概述
MC68HC08系列的单片机可以提供多个独立的定时器,例如, MC68HC908GP32芯片有两个定时器,分别叫定时器1、定时器2,它们的 工作原理是一致的,下面的说明均以定时器1为例。
linux内核定时器
linux内核定时器:
时钟中断: 有系统定时的硬件以周期性的时间间隔产生
比如HZ=1000,即1s中产生1000次中断,一次1/1000 s
每当时钟中断产生一次,jiffise (ulong)就加一,驱动程序根据jiffise值计算时间及间隔关机之后jiffise清零
一个延时程序:
ulong j=jiffise+jit_delay *HZ; //延时jit_delay秒
while(jiffse<j)
内核定时器用于控制某个函数在未来的某个特定的时刻执行, 特点,函数执行一次,就是一个单闹钟
内核定时器:内核定时器被组织成双向链表,使用一个结构体描述
struct timer_list {
struct list_head entry; //内核使用
ulong expires; //超时的jiffise值void (*funct)(ulong); //超时处理函数
ulong data; //超时处理函数的参数struct tvec_base *base; //内核使用
}
内核定时器:
void init_timer(struct timer_list *timer) //初始化定时器队列结构启动定时器:
void add_timer(struct timer_list *timer)
删除定时器, 如果超时之后,系统会自动删除定时器
int del_timer(struct timer_list *timer)
实例:。
内核定时器
内核定时器#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>//这两个头文件与内核定时器的使用有关;#include <linux/timer.h>#include <linux/jiffies.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("**********");MODULE_VERSION("2.6.35.000");//STEP1:定义一个内核定时器对象;static struct timer_list my_timer;/*STEP6:实现定时器函数;该定时器函数是由内核调用进程swapper 来执行的,即:内核调用进程swapper,然后由进程swapper来调用并执行该定时器函数;*/static void timer_process(unsigned long param){printk("HZ = %d, jiffies = %lu, timer parameter = %lu, file:%s, line:%d, caller:[%s];\n", HZ, jiffies, param, __FILE__, __LINE__, current->comm);/*STEP7:如果需要继续定时,那就需要把定时器对象重新加入到内核动态定时器链表中;因为定时器激活并到期之后,内核只会执行一次定时器函数,执行完之后,就把当前定时器对象从内核动态定时器链表中移除了;所以,如果要继续定时,那就要重新设定超时时间(旧的超时时间已经过期)并把当前定时器对象加入到内核动态定时器链表中并重新激活;*/#if 0my_timer.expires = jiffies + HZ; //重新设置定时器到期时间(100次时钟滴答:1秒);add_timer(&my_timer); //重新激活定时器;#endifmod_timer(&my_timer, (jiffies + HZ)); //重新设置超时时间并再次激活定时器;};static int __init study_init(void){int ret = 0;printk("%s\n", __PRETTY_FUNCTION__);//STEP2:初始化定时器对象my_timer;init_timer(&my_timer);//STEP3:设置定时器对象的各个属性值;my_timer.function = timer_process; //定时器函数;my_timer.data = (unsigned long)789; //定时器函数的参数;my_timer.expires = jiffies + HZ; //定时器到期时间(100次时钟滴答:1秒);//STEP4:注册内核定时器my_timer,把定时器对象my_timer注册到内核动态定时器链表中;add_timer()返回之后,定时器对象就由内核来接管了;add_timer(&my_timer);printk("kernel timer start; file:%s, line:%d, caller[%s]\n", __FILE__, __LINE__, current->comm);return ret;}static void __exit study_exit(void){printk("%s\n",__PRETTY_FUNCTION__);//STEP5:当定时器对象不需要时,就把定时器对象从内核动态定时器链表中删除;del_timer(&my_timer);printk("kernel timer stop;file:%s;line:%d\n", __FILE__, __LINE__);}module_init(study_init);module_exit(study_exit);定时器对象的定义:struct timer_list{struct list_head entry;unsigned long expires;struct tvec_base* base;void (*function)(unsigned long);unsigned long data;int slack;#ifdef CONFIG_TIMER_STATSvoid *start_site;char start_comm[16];int start_pid;#endif#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;#endif};其中:entry:双向链表元素,用于把多个定时器对象链接成一个双向循环队列;expires:定时器到期时间,单位是时钟滴答次数;这个时间被表示成自系统启动以来所走过的时钟滴答数(也即:时钟节拍或时钟中断数);当一个定时器的值expires值小于或等于jiffies的当前值时,我们就说这个定时器已经超时或到期了;在初始化一个定时器对象之后,通常把它的expires值设置成当前jiffies值加上某一个时间间隔值(以时钟滴答次数计算);内核会把该值与系统中的jiffies值进行比较;function:定时器处理函数;当定时器到期时,内核就会自动执行function所指定的函数;data:被传递给定时器函数function()的参数;通常,内核定时器对象被链接到一个双向循环队列中等待运行,此时我们就说该定时器处于pending状态,因此,函数timer_pending()就可以通过判断entry成员是否为空来判断一个定时器是否处于pending 状态;注意:1、定时器对象被注册到内核动态定时器链表中并激活之后,在定时时间到期时,定时器函数只会被内核调度执行一次,定时器函数执行结束之后,这个到期的定时器对象就会被内核从内核动态定时器链表中移除;因此,如果要实现间隔指定时间并重复定时的话,那就要重新设置超时时间(旧的超时时间已经过期)并把这个定时器对象重新注册到内核动态定时器链表中;2、当执行定时器函数时,当前进程是swapper,而不是加载模块时的insmod,也就是说,当调用add_timer()之后,系统就把定时器对象交由内核来管理了,当超时时间一到,内核就会调用进程swapper来执行定时器函数;也就是说,当超时时间到达之后,内核调用进程swapper,然后由进程swapper来调用并执行定时器函数;。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7
2.1.1 理想的HZ值
自Linux问世以来,i386体系结构中时 钟中断频率就设定为100HZ,但是在2.5开发 版本内核中,中断频率被提高到1000HZ。
提高节拍率意味着时钟中断产生得更 加频繁,所以中断处理程序也会更频繁的 执行,带来以下几点好处: • 更高的时钟中断解析度可提高时间驱动事 件的解析度。 • 提高了时间驱动事件的准确度。
13
2.2.1 jiffies的回绕
• Jiffies变量总是无符号长整数,因此,在32 位体系结构上时32位,在64位体系结构上 时64位。32位的jiffies变量,如果HZ = 100, 497天后会溢出,如果HZ = 1000,49.7天后 会溢出。而64位则别指望能看到溢出。
• 访问jiffies的代码仅会读取jiffies_64的低32位, 通过get_jiffies_64()函数,可以读取整个64 位,多数代码只需要访问低32位就够了。
/*还没有超时,继续执行任务*/ }
/*超时了,发生错误*/
15
• 正常的情况下,上面的代码没有问题。但是当 jiffies接近最大值的时候,就会出现回绕问题, 如下图所示:
• 1. 循环中第一次比较时,jiffies = J1,没有超时 • 2. 循环中第二次比较时,jiffies = J2,实际已经
执行中断处理程序,占用CPU时间过多。 • 减少了处理器对其他工作的时间,更频繁
的打乱处理器高速缓存并增加耗电。
11
2.2 jiffies
• 全局变量jiffies用来记录自系统启动以来产 生得节拍的总数。例如:系统启动了N秒, 那么jiffies就为N x HZ。
• Jiffies的类型为无符号长整型(unsigned long),用其它任何类型存放都不正确。
Linux 内核机制-定时器
参考资料: 《Linux内核设计与实现》(美)Robert Lห้องสมุดไป่ตู้ve著,
陈莉君 康华 译 原文第三版 , 机械工业出版社。 《深入Linux内核架构》 (德)Wolfgang Mauerer
著 , 郭旭 译 ,人民邮电出版社。 《深入理解Linux内核》 DANIEL P.BOVET & MARCO
• 节拍率(HZ)是时钟中断的频率,表示一 秒钟中断的次数。 例如:HZ=100,表示一秒内触发100次时钟 中断程序。 节拍率是通过静态预处理定义的,在系统 启动时按照HZ值对硬件进行设置。 不同的体系结构,HZ值也不同。
6
注意点:
• 在X86体系结构中,系统HZ默认值为100 • 内核在<asm/param.h>文件中定义了这个值 • 在编写内核代码时,HZ值不是一个固定不
8
提高节拍率等同于提供啊中断解析度。 例如:HZ=100的时钟执行粒度为10ms,, 即系统中周期事件最快为每10ms运行一次, 而不可能有更高的精度,但是当HZ = 1000 时,解析度就为1ms—精细了10倍。虽然内 核可以提供频度为1ms的时钟,但是并没有 证据显示对系统中所有的程序而言,频率 为1000HZ比100HZ的时钟更合适。
12
Jiffies定义于文件<linux/jiffies.h>中,格式如下:
extern u64 __jiffy_data jiffies_64; extern unsigned long volatile __jiffy_data jiffies; 使用例子如下: unsigned long time_tick = jiffies + 1; //从现在开始1个节拍 unsigned long later = jiffies + 5 * HZ; //从现在开始5秒
9
高HZ的优点
• 内核定时器能够以更高的频度和更高的准 确度运行。
• 依赖定时值执行的系统调用,比如poll() 和select(),能够以更高的精度运行。
• 对诸如资源消耗和系统运行时间等的测量 会有更精细的解析度。
• 提高进程抢占的准确度。
10
高HZ的缺点
• 时钟中断执行的越频繁,系统的负担越高 • 时钟中断频率越高,处理器必须花时间来
14
对于32位无符号长整型,最大取值为 2^32-1。所以在溢出之前,定时器节拍计数最 大为4294967295。如果节拍计数达到了最大值 后还要继续增加的话,它的值就会回绕到0。 比如下面的代码: unsigned long timeout = jiffies + HZ/2; //设置超时时间为0.5秒 while (timeout < jiffies) {
CESATI 著,陈莉君 张琼声 张宏伟 译 ,中国电力出版社。
1
1. 基本概念
• 在某些场景下,我们需要在特定的时间后 做某些动作,但是又不想一直等待而浪费 CPU,这时定时器是非常重要的。
• 定时器用于在将来某个时间点执行某个函 数以完成特定的任务 。
• Linux中内核定时器是基于软中断实现的, 也就是它处于中断上下文,而非进程上下 文。
超时了,但是jiffies超过最大值后又从0开始, 所以J2远远小于timeout • 3. while循环不会结束,相当于死循环。
16
内核提供四个宏来帮助比较节拍计数,能正确 处理节拍计数的回绕问题
• 内核可以通过调用in_atomic()判断当前是否 允许调度,不允许调度的情况包括:处于 中断上下文以及拥有自旋锁的上下文。
• 由于定时器异步执行,因而定时器处理函 数必须进行互斥保护。
4
2.在了解定时器之前先了解三个概念
• 节拍率:HZ • Jiffies • 时钟中断处理程序
5
2.1 节拍率:HZ
2
在非进程上下文需要遵循的原则
• 不允许访问用户空间 • Current无意义,因而也不可用 • 不能进行睡眠护着调度,不能调用schedule
或者某种wait_event,也不能调用任何可能 引起睡眠的函数,信号量也不可用,因为 信号量可能引起休眠。
3
如何判断中断上下文?
• 内核代码通过调用函数in_interrupt()可以判 断当前是否处于中断上下文,只要返回非0 就表示处于中断上下文。