分类: LINUX
2013-09-07 16:00:56
/**********************************************内核定时器相关操作*************************************************************/
/*====================延时=====================*/
/*
*1HZ=1s,它表示系统中中断发生的频率
*jiffies为内核计数器(记录当前时间),每隔1/HZ秒jiffies的值增1,驱动通常访问这个变量unsigned long time_val=jiffies;
*/
//下面的函数用于比较时间:
#include
int time_after(unsigned long a, unsigned long b);
int time_before(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
int time_before_eq(unsigned long a, unsigned long b);
//timespec和timeval与jiffies时间的相互转换函数:
#include
unsigned long timespec_to_jiffies(struct timespec *value);
void jiffies_to_timespec(unsigned long jiffies, struct timespec *value);
unsigned long timeval_to_jiffies(struct timeval *value);
void jiffies_to_timeval(unsigned long jiffies, struct timeval *value);
unsigned int inline jiffies_to_msecs(const unsigned long j);
unsigned int inline jiffies_to_usecs(const unsigned long j);
unsigned long msecs_to_jiffies(const unsigned int m);
unsigned long usecs_to_jiffies(const unsigned int u);
//延时:
#include
set_current_state(TASK_interruptible); //设置当前进程状态为阻塞(以便将进程在给定的时间内休眠)
schedule_timeout(delay); //将当前任务睡眠指定的时间后重新调度执行,正常返回值为0,除非在给定的超时时间到期之前返回
schedule_timeout_uninterruptible(delay);
schedule_timeout_interruptible(delay);
//短延时:
#include
void ndelay(unsigned long nsecs); //纳秒
void udelay(unsigned long usecs); //微妙
void mdelay(unsigned long msecs); //毫秒 //udelay和ndelay位传递给他们的值强加了上限,这点要注意 ,另外这三个延迟函数均是忙等待函数,因而在延迟过程中无法运行其他任务,
//我们应该在没有其他实用方法时使用这些函数
void msleep(unsigned int millisecs); //将调用它的进程休眠以给定的毫秒
unsigned long msleep_interruptible(unsigned int millisecs);//将调用它的进程休眠以给定的毫秒,其正常返回值是0,如果被提前唤醒,那么返回值就是剩余的毫秒数
void ssleep(unsigned int seconds); //将调用它的进程休眠以给定的秒
/*===============================================*/
/*==================内核定时器===================*/
/*
* 如果我们需要在将来的某个时间点调度执行某个函数,同时在该时间点到达之前不会阻塞当前进程(相当于中断),则可以使用内核定时器。内核定时器可用来在未来的某个
*特定时间点调度执行某个函数,从而可用于完成许多任务,一个内核定时器是一个数据结构,它告诉内核在用户定义的时间点使用用户定义的参数来执行一个用户
*定义的函数
* 内核定时器常常是作为“软件中断”的结果而运行的,定时器函数必须以自旋锁和原子上下文的方式原子地运行
* 内核定时器一个重要的特点是任务可以将自己注册以在稍后的时间重新启动
* 一个注册自己的定时器始终会在同一CPU上运行
* 即使在单处理器系统上,定时器也会是竞态的潜在的来源,这是由其异步执行的特点直接导致的,因此,任何通过定时器函数访问的数据结构都应该针对并发访问
*进行保护,可以使用原子变量或自旋锁
*/
//内核为驱动程序提供了一组用来声明、注册和删除内核定时器的函数,如下所示:
#include
struct timer_list { //该结构在使用前必须调用init_timer 或TIMER_INITIALIZER来初始化
struct list_head entry; //定时器列表
unsigned long expires; //表示期望定时器执行的jiffies值,到达该jiffies值时将调用function函数,并传递data作为参数(expires=jiffies+X*HZ,)
void (*function)(unsigned long);
unsigned long data; //function函数指针指向的的处理函数的参数,如果需要通过这个参数传递多个数据项,那么可以将这些数据项捆绑成一个数据结构,然后将该数据结构的指针强制转换成unsigned long 传入
//expires、function、data是可由定时器代码以外的代码访问的
struct tvec_base *base; //如果base为NULL,定时器尚未调度运行,否则该指针会告诉我们那个数据结构 ( 哪个cpu ) 在运行定时器
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
//上述该结构在使用前必须初始化,初始化可确保所有的字段被正确设置,包括那些对调用者不可见的字段,通过调用init_timer 或TIMER_INITIALIZER赋以某个静态的结构,即可完成初始化
//初始化之后,可在调用add_timer函数注册之前修改expires、function、data这三个公共字段,如果要在定时器到期前禁止一个已注册的定时器,则可以调用del_timer函数
struct timer_list timer; //定义一个定时器对象
void init_timer(struct timer_list *timer); //初始化定时器
或
struct timer_list TIMER_INITIALIZER(_function, _expires, _data);
void add_timer(struct timer_list *timer); //注册定时器(启动定时器)
int mod_timer(struct timer_list *timer,unsigned long expires); //更新某个定时的到期时间,经常用于超时定时器,我们也可以在通常使用add_timer的时候在不活动的定时器上调用 mod_timer(expires设定的时间值后再次启动定时器)
int del_timer(struct timer_list *timer); //注销定时器
int del_timer_sync(struct timer_list *timer); //和del_timer工作类似,但该函数可确保在返回时没有任何CPU在运行定时器函数,大多数情况下考虑使用它而不是del_timer
//在拥有锁时,应格外小心调用del_timer_sync,因为如果定时器函数企图获取相同的锁,系统就会进入死锁
int timer_pending(const struct timer_list *timer); //该函数通过读取timer_list结构不可见字段来返回定时器是否正在被调度运行
/*===============================================*/
/****************************************************end**********************************************************************/