Chinaunix首页 | 论坛 | 博客
  • 博客访问: 113702
  • 博文数量: 23
  • 博客积分: 471
  • 博客等级: 一等列兵
  • 技术积分: 251
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-21 15:21
文章分类
文章存档

2017年(1)

2013年(2)

2011年(20)

分类: LINUX

2011-08-24 14:06:01

1.内核定时器
 
   1.1  HZ和jiffies
 
   系统定时器以可编程的频率中断处理器,此频率即为每秒的定时器节拍数,对应着内核变量HZ,HZ越大,定时器间隔越小,进程调用的准确性也会越高,但是HZ越大也会导致开销和电源消耗增大,更多的处理器周期耗费在定时器中断上下文中。
   HZ的值取决于体系架构,通常为50-1200,定义在或者该文件包含的某个子平台相关的文件中。
 
   jiffies变量记录了系统启动以来,系统定时器已经触发的次数,内核每秒钟将jiffies变量增加HZ次,因此,对应HZ为100的系统,一个jiffy等于10ms,对应HZ为1000的系统,一个jiffy对应1ms。
   注意,jiffies变量定义为volatile,它告诉编译器不要优化该变量的存取,确保每次都会从内存去拿该数据,保证了该变量的最新状态。
 
下面的代码摘自drivers/ide/ide.c,使用到了jiffies和HZ
  1. unsigned int timeout = jiffies + (3*HZ); //timeout after 3s.

  2. while(hwgroup->busy){
  3.   /*...*/
  4.   if(time_after(jiffies,timeout))   // return -EBUSY after 3s if hwgroup is always busy.
  5.     return -EBUSY;
  6.   /*...*/
  7. }
 
   1.2  长延时
 
   在内核中,以jiffies为单位的延时都认为是长延时。长延时技术仅仅适用于进程上下文,因为睡眠等待不能用于中断上下文。
 
   几种长延时技术:
   ①.  忙等待:站着茅坑不拉屎,可能的代码片段如下:
  
  1. unsigned int timeout = jiffies + HZ;
  2. while(time_before(jiffies,timeout))
  3.   continue;

   ②. 睡眠等待:在等待过程中让出处理器,可能的代码片段如下:

  1. unsigned int timeout = HZ;
  2. schedule_timeout(timeout);
  3.   //另外两个用于睡眠等待的函数:  
      wait_event_timeout();  //在一个特定条件满足或者超时发生后,希望代码继续运行。
  msleep(); // ms as unit

   ③. 内核定时器API

  1. #include<linux/timer.h>

  2. struct timer_list my_timer;

  3. init_timer(&my_timer);
  4. my_timer.expire = jiffies + n * HZ;
  5. my_timer.function = timer_func;
  6. my_timer.data = func_parameter;
  7. add_timer(&my_timer);

  8. //上述代码只会让定时器运行一次,如果要周期性运行,需在timer_func中重新初始化一次

  9. static void timer_func(unsigned long func_parameter)
  10. {
  11.    /*...*/
  12.    init_timer(&my_timer);
  13.    my_timer.expire = jiffies + n * HZ;
  14.    my_timer.function = timer_func;
  15.    my_timer.data = func_parameter;
  16.    add_timer(&my_timer);

  17. }

另外还有mod_timer修改定时器expire时间,del_timer()取消定时器,或者用timer_pending()查看my_timer是否处于等待状态。查看kernel/timer.c发现schedule_timeout()内部使用了这些API.

   1.3  短延时

   在内核中,小于jiffies的延时认为是短延时,在进程上下文或者中断上下文都有可能发生,此时唯一的解决办法就是使用忙等待。

   实现短延时的API包括: 

     #include 
     void mdelay(unsigned long);
  1. void udelay(unsigned long);
  2. void ndelay(unsigned long);

这三个函数分别对应ms,us,ns级的短延时,具体实现取决于体系架构。

  忙等待的实现方法是测量处理器执行一条指令的时间,为了延时,执行一定数量的指令。

2.延缓操作
 
  中断处理程序要求尽可能的快,但是如果我们需要在响应中断处理中完成大量的设备数据处理,此时就产生了一个矛盾,因此中断处理过程被分成两部分:一个急切抢占并与硬件交互的顶半部,一个处理所有使能的中断的并不急切的底半部。如下三种机制可以将工作解析到底半部执行:
 
   *  softirq
   *  tasklet
   *  work queue
 
下图对三种机制进行了对比:
阅读(2124) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~