1、使用jiffies计数器
需包含头文件<linux/jiffies.h>(
注:在本人测试的时候系统找不到该头文件,不知道是不是本书的错误之处,在linux系统编程中Robert Love 这样注明的: The Linux kernel now supports “tickless” operation, so this is no longer strictly true.)
2、处理器特定的寄存器
(1)需包含头文件<asm/msr.h>(x86专用的头文件)
rdtsc(low32, high32);
rdtscl(low32);
rdtscll(var64);
(2)其他平台也提供了一个与平台无关的功能,在<asm/timex.h>(由<linux/timex.h>包含),其原型如下:
#include <linux/timex.h>
cycles_t get_cycles(void);
3、获取当前时间
将墙钟时间转换为jiffies值的函数:
unsigned long mktime(unsigned int year, unsigned int mon, unsigned int day,
unsigned int hour, unsigned int min, unsigned int sec);
4、延迟执行
(1)长延迟
1)忙等待(
注:最好不用)
while (time_before(jiffies, ji))
cpu_relax();
2)让出处理器
#include <linux/sched.h>
while (time_before(jiffies, ji)){
schedule();
}
3)超时
如果驱动程序受用等待队列来等待其他一些时间,而我们同时希望在特定时间段中运行,怎可以使用:
#include <linux/wait.h>
long wait_event_timeout(wait_queue_head_t a, condition, long timeout);
或
long wait_queue_interruptible_timeout(wait_queue_head_t q, condition, long timeout);
不等待特定事件的延迟,内核为我们提供了:
#include <linux/sched.h>
singed long schedule_timeout(signed long timeout);
(2)短延迟
#include <linux/delay.h> //这些函数实际包含在<asm/delay.h>中
void ndelay(unsigned long nsecs); //纳秒时间
void udelay(unsigned long usecs); //微秒时间
void mdelay(unsigned long msecs);
//毫秒时间
实现毫秒级(或者更长)延迟还有另外一种方法,这种方法不涉及忙等待在<linux/delay.h>文件声明了下面这些函数:
void msleep(unsigned int millisecs);
unsigned long msleep_interruptiable(unsigned int maillisecs);
void ssleep(unsigned int seconds);
5、定时器API
内核为驱动程序提供了一组用来声明、注册和删除内核定时器的函数。
#include <linux/timer.h>
struct timer_list {
/*......*/
unsigned long expires;
void (*function) (unsigned long);
unsigned long data;
};
void init_timer(struct timer_list * timer);
struct timer_list TIMER_INITIALIZER(_function, _expires, _data);
void add_timer(struct timer_list * timer);
int del_timer(struct timer_lsit * timer);
其他几个内核定时器API:
int mod_timer(struct timer_list *timer, unsigned long expires);
int del_timer_sync(struct timer_list *timer);
int timer_pending(const struct timer_list *timer);
6、内核定时器的实现
7、tasklet
#include <linux/interrupt.h>
struct tasklet_struct {
/*......*/
void (*func) (unsigned long);
unsigned long data;
};
void tasklet_init(struct tasklet_struct *t, void (*func) (unsigned long), unsigned long data);
DECLARE_TASKLET(name, func, data);
DECLARE_DISABLED(name, func, data);
tasklet相关内核接口:
void tasklet_disable(struct tasklet_struct *t);
void tasklet_disable_nosync(struct tasklet_struct *t);
void tasklet_enalbe(struct tasklet_struct *t);
void tasklet_schedule(struct tasklet_struct *t);
void tasklet_hi_schedule(struct tasklet_struct *t);
void tasklet_kill(struct tasklet_struct *t);
8、工作队列
注:工作队列与tasklet的关键区别:tasklet会在很短的时间内很快执行,并且以原子模式执行,而工作队列函数可以具有更长的延迟并且不比原子化。
(1)工作队列有struct workqueue_struct 类型定义在<linux/workqueue.h>:
使用下面的两个函数之一建立工作队列:
struct workqueue_struct *create_workqueue(const char *name);//在每个处理器上创建专用线程
struct workqueue_struct *create_singlethread_workqueue(const char *name);//只在一个处理器上创建专用线程
在向工作队列提交一个任务时,用下面的宏定义填充一个work_struct结构:
DECLARE_WORK(name, void (*function) (void *), void *data);//编译时完成
OR
INIT_WORK(struct work_struct *work, void (*function) (*void), void *data); //运行时构
PREPARE_WORK(struct work_struct *work, void (*function) (void *), void *data);//造
(2)如果将工作提交到工作队列,则可使用下面的两个函数之一:
int queue_work(struct workqueue_struct *queue, struct work_struct *work);
int queue_delayed_work(strcut workqueue_struct *queue, struct work_struct *work, unsigned long delay);
(3)为了确保int cancel_delayed_work(struct workqueue_srtuct *queue )函数返回0之后,工作函数不会系统中任何地方运行,则应该调用下面的函数:
void flush_workqueue(struct workqueue_struct *queue);
(4)释放相关资源:
void destroy_workqueue(struct workqueue_struct *queue);
9、共享队列