LInux定时器.

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Linux中的时钟和定时测量定时测量Linux内核提供两种主要的定时测量获得当前的时间和日期系统调用:time(),ftime()以及gettimeofday()维持定时器settimer(),alarm()定时测量是由基于固定频率振荡器和计数器的几个硬件电路完成的RTC等等2020/1/11嵌入式OS2硬时钟80x86体系结构上,内核必须显式的与四种时钟打交道实时时钟Realtimeclock,RTC时间戳计数器Timestampcounter,TSC可编程间隔定时器Programmableintervaltimer,PITCPU本地定时器高精度事件定时器ACPI电源管理定时器用于跟踪当前时间产生周期性的时钟中断,用于计时实时时钟RTC基本上所有的PC都包含实时时钟独立于CPU与所有其他芯片依靠一个独立的小电池供电给RTC中的振荡器即使关闭PC电源,还会继续运转与CMOSRAM往往集成在一个芯片内例如:Motorala146818能在IRQ8上发出周期性的中断,频率在2HZ~8192之间可以对其编程实现一个闹钟Linux本身只使用RTC获得时间和日期对应的设备文件为/dev/rtc可以通过设备文件对其编程内核通过0x70和0x71两个端口访问RTC系统管理员可以通过执行时钟程序设置时钟时间戳计数器TSC在80x86微处理器中,有一个CLK输入引线接收外部振荡器的时钟信号从pentium开始,很多80x86微处理器都引入了一个TSC一个64位的、用作时间戳计数器的寄存器它在每个时钟信号(CLK)到来时+1例如时钟频率400MHz的微处理器,TSC每2.5ns就+1rdtsc指令用于读该寄存器注意使用这个寄存器时,内核必须考虑时钟信号的频率在Linux2.6.26中,rdtscll()和rdtscl()用来读取TSC的值。rdtscl:32位rdtscll:64位native_read_tsc与后面介绍的可编程间隔定时器相比,TSC可以获得更精确的时钟为此,Linux在系统初始化的时候必须确定时钟信号CLK的频率(即CPU的实际频率)如何获得CPU实际频率tsc_calibratetsc_calibrate根据在一个相对较长的时间间隔内(约5ms)所发生的TSC计数的个数进行计算那个间隔由可编程间隔定时器给出由于只在系统初始化的时候运行一次,因此本程序可以执行较长时间,而不会引起问题可编程间隔定时器PIT经过适当编程后,可以周期性的给出时钟中断通常是8254CMOS芯片使用I/O端口0x40~0x43Linux将PIT编程为:100Hz、1000Hz通过IRQ0发出时钟中断每若干毫秒(100Hz为10ms)产生一次时钟中断,即一个tickTick的长短短优点:分辨率高缺点:需要较多的CPU时间处理,会导致用户程序运行变慢适用于非常强大的机器,这种机器能够承担较大的系统开销Tick的长短设置取决于硬件体系结构的快慢一个折中,例如在大多数惠普的Alpha和Intel的IA-64上约1ms产生一个tickRawhideAlpha工作站采用更高(1200tick/秒)与系统时钟相关的宏定义(1)宏定义HZ。宏定义Hz记录了不同体系结构下,系统时钟所要求的可编程定时器产生中断的频率。(2)宏定义CLOCK_TICK_RATE。宏定义CLOCK_TICK_RATE记录了不同体系结构下,驱动可编程定时器工作的输入时钟频率。(3)宏定义LATCH。宏定义LATCH记录了上述两个宏定义的比值,用于在内核初始化过程中设置可编程定时器中计数器寄存器counter的初始值。下列宏决定时钟中断频率在Linux中,下列宏决定时钟中断频率对8254分频,获得HZ所需的时钟HZ:每秒钟时钟中断的个数,即每秒tick的个数8254芯片的内部振荡器频率,每秒多少次在init_pit_timer()中初始化时钟中断频率此后,只要允许处理时钟中断,约每10ms就会产生一个时钟中断1tick约为10ms(当HZ=100)Linux的计时体系结构更新自系统启动以来所经过的时间更新时间和日期确定当前进程的执行时间,考虑是否要抢占更新资源使用统计计数检查到期的软定时器定时器是一种软件功能,即允许在将来的某个时刻,函数在给定的时间间隔用完时被调用2020/1/11嵌入式OS15在单处理器系统中,所有定时活动都由IRQ0上的时钟中断触发,包括在中断中立即执行的部分,和作为下半部分延迟执行的部分计时体系结构中的关键数据结构和变量计时时钟源Jiffies变量Xtime变量2020/1/11嵌入式OS17时钟源时钟源抽象参见数据结构clocksource缺省时钟源注册时钟源:clocksource_registerclocksource_list按rating排序Jiffies时钟源(缺省时钟源)以tsc作为时钟源pit作为时钟源init_pit_clocksource将会注册此时钟源注册pit作为时钟源注册好的时钟源链表clocksource_list按rating排序,靠前会被选中相对时间和墙上时间相对时间:记录从系统启动直到当前时刻的系统时钟产生的滴答数,存储于系统核心变量jiffies(jiffies_64);相对时间由系统时钟中断进行维护,该变量记录了系统启动到当前时刻为止系统时钟产生中断的次数,用于提示内核或用户进程一段指定的时间已经过去了。墙上时间:系统的当前时间xtimeJiffies变量记录系统自启动以来系统产生的tick数每次时钟中断+1(在系统响应时钟中断,时钟中断处理程序timer_interrupt()将该变量的值加1)因为一秒钟内产生系统时钟中断次数等于宏定义HZ的值,所以变量jiffies的值在一秒内增加HZ。关于jiffies_642020/1/11嵌入式OS26jiffies溢出处理示例程序jiffies溢出导致逻辑错误用于jiffies比较的宏定义为了防止jiffies回绕造成程序的逻辑错误,Linux内核中提供了以下4个宏定义用于jiffies间的比较。time_after(a,b)time_before(a,b)time_after_eq(a,b)time_before_eq(a,b)采用这4个宏定义进行jiffies间的比较,可以有效地解决因jiffies溢出造成的程序逻辑出错。通过宏定义修复jiffies溢出导致逻辑错误墙上时间墙上时间,在系统启动过程中根据实时钟(RTC)芯片保存数据进行初始化,在系统运行期间由系统时钟维护并在合适的时刻和RTC芯片进行同步。墙上时间存储于系统核心变量xtime中,该变量记录了现实世界中的年月日格式的时间,以便内核对某些对象和事件作时间标记,如记录文件的创建时间、修改时间、上次访问时间,或者供用户进程通过系统调用来使用。Xtime变量存放当前时间和日期kernel/time/timekeeping.c2020/1/11嵌入式OS31该结构用来表示当前时刻距UNIX时间基准1970/01/01/00:00:00的相对时间。时间纪元1970年1月1日(UTC)午夜include/linux/time.h该结构用来表示当前时刻距UNIX时间基准1970/01/01/00:00:00的相对时间。2020/1/11嵌入式OS32变量xtime的初值在系统初始化过程通过读取系统实时钟芯片RTC的值来为变量xtime赋初值;该变量的值在系统运行过程中由系统时钟中断处理程序负责在每次时钟中断时进行更新。该变量的初始化语句如下。xtime.tv_sec=get_cmos_time();xtime.tv_nsec=(INITIAL_JIFFIES%HZ)*(NSEC_PER_SEC/HZ);Xtime的更新基本上每个tick更新一次参见:update_wall_time根据时钟源来更新xtime的秒数和纳秒数时钟源timekeeping_initXtime相关初始化,并确定Xtime的相关时钟源kernel/time/timekeeping.ckernel/time/timekeeping.c2020/1/11嵌入式OS34X86中的时钟中断源及其初始化start_kernelinit_timers定时机制相关初始化hrtimers_init高精度定时器相关初始化timekeeping_initXtime相关初始化time_inithpet_time_initsetup_pit_timer注册pit_clockevent为Clockevent设备并设置global_clock_eventtick_init滴答相关初始化sched_clock_init调度相关时钟初始化setup_pit_timer注册pit_clockevent为Clockevent设备并设置global_clock_eventPit功能函数确定time_init_hook()来设置系统时钟中断处理程序。时钟中断处理函数=&pit_clockeventglobal_clock_event在setup_pit_timer中被初始化为pit_clockevent其event_handler在注册过程中,被初始化为tick_handle_periodictick_handle_periodic的关键是tick_periodic,该函数调用do_timer和update_process_timesupdate_process_timestick_periodictick_set_periodic_handlertick_setup_periodictick_setup_devicetick_check_new_devicetick_init调用clockevents_register_notifier注册tick_notifier到clockevents_chain上notifier_call_chain将会遍历clockevents_chain__raw_notifier_call_chainraw_notifier_call_chainclockevents_do_notifyclockevents_register_devicedo_timer设置event_handler=tick_handle_periodickernel/timer.c2020/1/11嵌入式OS46Update_wall_time()完成变量xtime的更新kernel/timer.ckernel/time/timekeeping.c2020/1/11嵌入式OS47Raise_softirq()激活本地CPU上的软件定时器中断任务队列。Scheduler_tick该函数使当前进程的时间片计数器减一。kernel/timer.c2020/1/11嵌入式OS48软定时器和延迟函数软定时器动态定时器(内核)间隔定时器(可以用户)延迟函数2020/1/11嵌入式OS49动态定时器动态定时器被动态的创建和撤销,当前活动的动态定时器个数没有限制include/linux/timer.h2020/1/11嵌入式OS50动态定时器的数据结构expires用于和系统核心变量jiffies进行比较。成员变量function:该函数指针变量保存了内核定时器超时后要执行的函数,即定时器超时处理函数。成员变量data:该无符号长整型变量用作定时器超时处理函数的参数。成员变量base:该指针变量表明了该内核定时器节点归属于系统中哪一个处理器,在使用函数init_timer()初始化内核定时器节点的过程中,将该指针指向了一个每处理器变量tvec_bases的成员变量t_base。创建并激活一个动态定时器创建一个新的timer_list对象调用init_ti

1 / 77
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功