En 0755-86038900
公司新闻

4412开发板android入门篇_Linux内核时间管理

发布时间:2015-03-17

Linux内核定时器的使用


linux内核中定时器的使用,定时器是很重要的内容,在调试TP或者其他许多程序时都涉及到定时器的使用,因此掌握定时器的运用是必备的。


下面将介绍定时器驱动的常用函数。对于具体的驱动后面的文档会以蜂鸣器驱动为例,并介绍框架层及应用怎样去控制蜂鸣器。


1.linux系统时间频率定义


系统定时器的时钟频率HZ 定义在 arch/arm/include/asm/param.h


#define  Hz  100  //ARM构架基本都是100


2.节拍总数(jiffies)


 全局变量jiffies用来记录自系统启动以来产生的节拍总数,根据这个节拍总数可以获得系统自启动以来的时间,linux系统启动时,会将jiffies初始化为0,


3.访问jiffies变量


 jiffies总是无符号长整数,该变量定义在linux/jiffies.h文件中


内核定时器


使用内核定时器的步骤


1. 定义内核定时器结构体变量


 内核定时器需要一个timer_list结构体(#include<linux/timer.h>),该结构体指定的内核定时器处理函数等


struct timer_list {


 struct list_head entry;      //定时器链表入口


 unsigned long expires;   //以jifffies为单位的定时值(过期时间)


 struct tvec_base *base;   // 定时器内部值,用户不要使用


 void (*function)(unsigned long);     // 定时器处理函数


 unsigned long data;                          //传给处理函数的长整形参数值


 int slack;                                             //与expires组合成新的expires,在第二部会初始化这个变量


#ifdef CONFIG_TIMER_STATS


 int start_pid;


 void *start_site;


 char start_comm[16];


#endif


#ifdef CONFIG_LOCKDEP


 struct lockdep_map lockdep_map;


#endif


};


2.初始化内核定时器(实际初始化timer_list 结构体)


初始化内核定时器需要使用init_timer宏(#include<linux/timer.h>),该宏原型如下:


#define init_timer(timer)       init_timer_key((timer), NULL, NULL) 


 其中timer就是timer_list的指针,init_timer主要调用了init_timer_key函数


void init_timer_key(struct timer_list *timer,  const char *name, struct lock_class_key *key) 


{


 debug_init(timer);


 __init_timer(timer, name, key);


}


static void __init_timer(struct timer_list *timer,


    const char *name,


    struct lock_class_key *key)


{


 timer->entry.next = NULL;


 timer->base = __raw_get_cpu_var(tvec_bases);


 timer->slack = -1;


#ifdef CONFIG_TIMER_STATS


 timer->start_site = NULL;


 timer->start_pid = -1;


 memset(timer->start_comm, 0, TASK_COMM_LEN);


#endif


 lockdep_init_map(&timer->lockdep_map, name, key, 0);


}


3.实现定时器处理函数


定时器处理函数原型如下:


  void  timer_handle(unsigned long arg)   //arg就是  timer_list .data的值


4.对timer_list 成员变量的进一步初始化


初始化function函数和expires的值,到达过期时间expires时执行function函数。


5.激活定时器


  定时器激活才能使用。使用add_timer函数才能激活定时器,add_timer函数原型如下:


void add_timer(struct timer_list *timer)


{


 BUG_ON(timer_pending(timer));


 mod_timer(timer, timer->expires);


}


int mod_timer(struct timer_list *timer, unsigned long expires)


{


 expires = apply_slack(timer, expires);


 /*


  * This is a common optimization triggered by the


  * networking code - if the timer is re-modified


  * to be the same thing then just return:


  */


 if (timer_pending(timer) && timer->expires == expires)


  return 1;


 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);


}


6.停止定时器


如果要在定时器到期之前停止定时器,可以使用如下函数:


int del_timer(struct timer_list *timer)


int del_timer_sync(struct timer_list *timer)


无论定时器是否被激活都可以使用这两个函数,未被激活是函数返回0,否则返回1,多处理器都在用定时器时使用此函数del_timer_sync


停止定时器。但此函数不能用在中断上下文中,(因为该函数可能引起阻塞)。


内核延迟


1.忙等待


 使用方法


  unsigned long  delay=jiffies + 5 * Hz;


  ............................................


  while(time_before(jiffies,delay))


   cond_resched();


2.短延迟


 linux/delay.h


ndelay(unsigned long x);  //延迟x纳秒


udelay(unsigned long x);  //延迟x微秒


mdelay(unsigned long x);  //延迟x毫秒


以上几个宏的实现原理是忙等待,会占用大量CPU资源,所以用下面的函数延时较好


msleep(unsigned int msecs)  //延迟msecs毫秒


msleep_interruptible(unsigned int msecs)  //延迟msecs毫秒,,可被中断打断


ssleep(unsigned int seconds)          //延迟seconds秒