Linux操作系统分析(5)- 计时器

一、提要      

        计时器属于操作系统中的基础组件,不管是用户空间的程序开发,还是内核空间的程序开发,很多时候都需要有定时器作为基础组件的支持。使用定时器的目的无非是为了周期性的执行某一任务,或者是到了一个指定时间去执行某一个任务。

        本文首先讨论了在 Linux 环境下,计时器的分类与实现,并对相应的接口函数进行使用。


二、计时器的种类

RTC(Real Time Clock)

实时时钟,独立于CPU和其他所有芯片,能够在IRQ8上发出周期性的中断,频率在2Hz-8192Hz之间。


TSC(Time Stamp Counter)

时间戳计时器,主体是位于CPU里面的一个64位的TSC寄存器。每个CPU时钟周期其值加一。可以通过汇编语言指令rdtsc读这个寄存器。


PIT(Programmable Interval Timer)

可编程间隔定时器,通过发出一个特殊的中断来通知内核一个时间间隔过去了,PIT永远以内核确定的固定频率不停地发出中断。


APIC - CPU本地定时器


HPET - 高精度事件定时器


ACPI 电源管理定时器


三、计时体系的结构

内核会周期性地做下面的事:

1)更新系统启动以来所经过的时间;

2)更新时间和日期;

3)处理时间片的分配;

4)更新资源使用统计数;

5)检查每个软定时器的时间间隔是否已到。


计时器的初始化

1)初始化xtime变量(存放当前时间和日期);

2)初始化wall_to_monotonic变量;

3)如果内核支持HPET,它将调用hpet_enable函数来确认ACPI固件是否探测到了该芯片并将它的寄存器映射到了内存地址空间中;

4)调用select_timer()来挑选系统中可利用的最好的定时器资源(精度优先),设置cur_timer变量指向该定时器资源对应的定时器对象的地址;

5)调用setup_irq(0,&irq0)来创建与IRQ0相应的中断门,IRQ0引脚连接着系统时钟的中断源(PIT或者HPET).


时钟终端处理程序的执行

1)在xtime_lock顺序锁上产生一个write_seqlock()来保护与定时器相关的内核变量;

2)执行cur_timer定时器对象的mark_offset方法。cur_timer指向的定时器在计时器的初始化已确定;

3)调用do_timer_interrupt()函数;

4)调用write_sequnlock释放xtime_lock顺序锁;

5)返回1,报告中断已经有效处理了。


Linux考虑两种类型的定时器,动态定时器(dynamic timer)和间隔定时器(interval timer)。第一种类型由内核使用,后者可以由进程在用户态创建。


创建动态定时器的步骤

1)创建一个新的timer_list对象(静态全局变量、定义局部变量、动态分配);

2)调用init_timer(&t)初始化这个对象;

3)把定时器到期时要激活的函数地址放入function字段;

4)如果动态定时器还没有被插入到链表中,如expires字段赋一个合适的值并调用add_timer(&t)把t插入链表;

5)如已插入,调用mod_timer()来更新expires字段。


三、计时器的使用

unsigned int alarm(unsigned int seconds);
函数说明: alarm()用来设置信号SIGA
LRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

返回值: 返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。
alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。

例子:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4.   
  5. void alarm_handler(int a){  
  6.     printf("Timer is up!\n");  
  7.     alarm(3);  
  8. }  
  9.   
  10. int main()  
  11. {  
  12.     signal(SIGALRM,alarm_handler);  
  13.     alarm(1);   while(1) {};  
  14.     return 1;  
  15. }  

执行 结果:




int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()比alarm功能强大,支持3种类型的定时器:

ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
setitimer()调用成功返回0,否则返回-1。


相关结构体:


struct itimercal:
           struct itimerval {
           struct timeval it_interval; /* timer interval */
           struct timeval it_value; /* current value *
};

struct timeval {
    long tv_sec; 
    long tv_usec; 
};

itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了. 然后再将it_value设置为it_interval值.这样就实现了轮询的定时,而不是想alarm那样只能定时一次,而且其精确度也很高。


例子:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4. #include <sys/time.h>  
  5.   
  6. void alarm_handler(int sig){  
  7.     switch(sig)  
  8.     {  
  9.         case SIGALRM:  
  10.             printf("Catch a SIGALRM!\n");  
  11.             break;  
  12.         case SIGVTALRM:  
  13.             printf("Catch a SIGVTALRM!\n");  
  14.             break;  
  15.     }  
  16.     return;  
  17. }  
  18.   
  19. int main()  
  20. {  
  21.     struct itimerval value, ovalue, value2;            
  22.     signal(SIGALRM, alarm_handler);  
  23.     signal(SIGVTALRM, alarm_handler);  
  24.     value.it_value.tv_sec = 1;  
  25.     value.it_value.tv_usec = 0;  
  26.     value.it_interval.tv_sec = 1;  
  27.     value.it_interval.tv_usec = 0;  
  28.     setitimer(ITIMER_REAL, &value, &ovalue);  
  29.     value2.it_value.tv_sec = 0;  
  30.     value2.it_value.tv_usec = 500000;  
  31.     value2.it_interval.tv_sec = 0;  
  32.     value2.it_interval.tv_usec = 500000;  
  33.     setitimer(ITIMER_VIRTUAL, &value2, &ovalue);  
  34.     while(1);  
  35.     return 1;  
  36.   
  37. }  

执行:



四、参考

understanding the kernel  3rd Edith

linux应用层定时器与休眠 - http://blog.csdn.net/max415/article/details/2315977

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值