内核在硬件的帮助下计算和管理时间。硬件为内核提供一个系统定时器用以计算流逝的时间。系
统定时器以某种频率自行触发,产生时钟中断,进入内核时钟中断处理程序中进行处理。
墙上时间和系统运行时间根据时钟间隔来计算。
利用时间中断周期执行的工作:
更新系统运行时间;
更新实际时间;
在smp系统上,均衡调度程序中各处理器上运行队列;
检查当前进程是否用尽了时间片,重新进行调度;
运行超时的动态定时器;
更新资源消耗和处理器时间的统计值;
二 节拍率系统定时器的频率;通过静态预处理定义的——HZ;系统启动按照HZ值对硬件进行设置。体系结构不同,HZ值也不同;HZ可变的。
//内核时间频率
#define HZ 1000
提高节拍率中断产生更加频繁带来的好处:
提高时间驱动事件的解析度;
提高时间驱动事件的准确度;
内核定时器以更高的频度和准确度;
依赖顶上执行的系统调用poll()和select()能更高的精度运行;
系统时间测量更精细;
提高进程抢占的准确度;
提高节拍率带来的副作用:
中断频率增高系统负担增加;
中断处理程序占用处理器时间增多;
频繁打断处理器高速缓存;
节拍率HZ值需要在其中进行平衡。
三 jiffies
jiffies:全局变量,用来记录自系统启动以来产生的节拍总数。启动时内核将该变量初始化为0;
此后每次时钟中断处理程序增加该变量的值。每一秒钟中断次数HZ,jiffies一秒内增加HZ。系统运行时间 = jiffie/HZ.
jiffies用途:计算流逝时间和时间管理
jiffies内部表示:
extern u64 jiffies_64;
extern unsigned long volatile jiffies; //位长更系统有关32/64
32位:497天后溢出
64位:……
//0.5秒后超时 unsigned long timeout = jiffies + HZ/2; …… //注意jiffies值溢出回绕用宏time_before 而非 直timeout > jiffies if(time_before(jiffies,timeout)){ //没有超时 }else{ //超时 }
四 硬时钟和定时器
两种设备进行计时:系统定时器和实时时钟。
实时时钟(RTC):用来持久存放系统时间的设备,即便系统关闭后,靠主板上的微型电池提供电力保持系统的计时。
系统启动内核通过读取RTC来初始化墙上时间,改时间存放在xtime变量中。
系统定时器:内核定时机制,注册中断处理程序,周期性触发中断,响应中断处理程序,进行处理执行以下工作:
l 获得xtime_lock锁,访问jiffies和更新墙上时间xtime;
l 更新实时时钟;
l 更新资源统计值:当前进程耗时,系统时间等;
l 执行已到期的动态定时器;
l 执行scheduler_tick()
//中断处理程序 irqreturn_t timer_interrupt(int irq, void *dev) { //ticks have passed long nticks; xtime_update(nticks); while (nticks--) update_process_times(user_mode(get_irq_regs())); return IRQ_HANDLED; } void xtime_update(unsigned long ticks) { //seq锁 write_seqlock(&xtime_lock); do_timer(ticks); write_sequnlock(&xtime_lock); } void do_timer(unsigned long ticks) { jiffies_64 += ticks; //更新墙上时间 ——实际时间 update_wall_time(); calc_global_load(ticks); } void update_process_times(int user_tick) { struct task_struct *p = current; //计算当前进程执行时间 account_process_tick(p, user_tick); //触发软中断TIMER_SOFTIRQ 超时的timer run_local_timers(); //计算进程时间片 scheduler_tick(); }
五 定时器
定时器:管理内核时间的基础,推后或执行时间执行某些代码。
定时器数据结构:
struct timer_list { struct list_head entry; //定时值基于jiffies unsigned long expires; //定时器内部值 struct tvec_base *base; //定时器处理函数 void (*function)(unsigned long); //定时器处理函数参数 unsigned long data; …… };
定时器使用:
struct timer_list my_timer; //初始化定时器 init_timer(&my_timer); …… //激活定时器 add_timer(&my_timer); //删除定时器 del_timer(my_timer); ……
六 延迟执行
使用定时器和下半部机制推迟执行任务。还有其他延迟执行的机制:
忙等待:
利用节拍,精确率不高
unsigned long delay = jiffies + 2*HZ ; //2秒 节拍整数倍才行;
while(time_before(jiffies,delay))
;
短延迟:延迟时间精确到毫秒,微妙;短暂等待某个动作完成时,比时钟节拍更短;依靠数次循环达到延迟效果。
void udelay(unsigned long usecs)
void mdelay(unsigned long msecs)
schedule_timeout()延迟:使执行的任务睡眠指定时间,达到延迟
signed long __sched schedule_timeout(signed long timeout) { struct timer_list timer; unsigned long expire; switch (timeout) { case MAX_SCHEDULE_TIMEOUT: //无限期睡眠 schedule(); goto out; default: if (timeout < 0) { current->state = TASK_RUNNING; goto out; } } //超时时间 expire = timeout + jiffies; //初始化一个timer定时器 参数current task setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); /* Remove the timer from the object tracker */ destroy_timer_on_stack(&timer); timeout = expire - jiffies; out: return timeout < 0 ? 0 : timeout; } static void process_timeout(unsigned long __data) { //唤醒被睡眠的任务 wake_up_process((struct task_struct *)__data); }