1. 内核定时器: 内核在时钟中断发生后检测各定时器是否到期,在Linux内核中提供了一组函数和数据结构来完成定时触发工作/周期的事务。
timer_list 结构体: – 表示一个定时器struct timer_list { struct list_head entry; /* 定时器列表 */ unsigned long expires; /*定时器到期时间*/ void (*function)(unsigned long); /* 定时器处理函数 */ unsigned long data; /* 作为参数被传入定时器处理函数 */ struct timer_base_s *base; ... }; 12345678
12345678
expires,定时器的到期时间,单位是jiffies
function,定时器到期,要执行的函数
data,传入要执行的函数的参数
初始化定时器:1.void init_timer(struct timer_list * timer);
功能是初始化 timer_list 结构体的 entry 的next 为 NULL,并给 base 指针赋值
2.TIMER_INITIALIZER(_function, _expires, _data)
功能是赋值 timer_list 结构体的 function、expires、data和 base 成员
函数原型是:
#define TIMER_INITIALIZER(_function, _expires, _data) { \ .entry = { .prev = TIMER_ENTRY_STATIC }, \ .function = (_function), \ .expires = (_expires), \ .data = (_data), \ .base = &boot_tvec_bases, \ } 1234567
1234567
3.DEFINE_TIMER(_name, _function, _expires, _data)
一个给结构体赋值的快捷方式,
函数原型是:
#define DEFINE_TIMER(_name, _function, _expires, _data) \ struct timer_list _name = \ TIMER_INITIALIZER(_function, _expires, _data) 123
123
4.static inline void
setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data)
这个函数也可以给 定时器 结构体成员赋值,
函数原型是:
static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data) { timer->function = function; timer->data = data; init_timer(timer); } 12345678
12345678
增加定时器:void add_timer(struct timer_list * timer);
注册内核定时器,将定时器加入到内核动态定时器链表,即启动定时器
删除定时器:int del_timer(struct timer_list * timer); –> 直接删除
int del_timer_sync(struct timer_list * timer); –> 等待定时器处理完之后删除,此函数不能出现在中断上下文。一般用在多 CPU 场合,定时器被另一个 CPU 使用的情况。
修改定时器:int mod_timer(struct timer_list *timer, unsigned long expires);
这个函数有启动定时器的功能
使用思路:open 函数中setup_timer,想要用定时器的地方mod_timer.定义 timer_list 结构体,在想要调用的地方填充上 timer_list里边的成员,init_timer,add_timer
注意事项:定时器的每次添加之后,执行完定时器后就会失效,要想循环使用,需要在定时函数中添加del_timer 是删除没有发生的定时器,如果已经发生了,删除不删除应该无所谓
使用模板: /*xxx 设备结构体*/ struct xxx_dev { struct cdev cdev; ... timer_list xxx_timer;/*设备要使用的定时器*/ }; /*xxx 驱动中的某函数*/ xxx_func1(…) { struct xxx_dev *dev = filp->private_data; ... /*初始化定时器*/ init_timer(&dev->xxx_timer); dev->xxx_timer.function = &xxx_do_timer; dev->xxx_timer.data = (unsigned long)dev; /*设备结构体指针作为定时器处理函数参数*/ dev->xxx_timer.expires = jiffies + delay; /* 定时器的到期时间往往是目前 jiffies 的基础上添加一个时延,若为 Hz,则表示延迟 1s。 */ /*添加(注册)定时器*/ add_timer(&dev->xxx_timer); ... } /*xxx 驱动中的某函数*/ xxx_func2(…) { ... /*删除定时器*/ del_timer (&dev->xxx_timer); ... } /*定时器处理函数*/ static void xxx_do_timer(unsigned long arg) { struct xxx_device *dev = (struct xxx_device *)(arg); ... /*调度定时器再执行*/ dev->xxx_timer.expires = jiffies + delay; add_timer(&dev->xxx_timer); ... }1234567891011121314151617181920212223242526272829303132333435363738394041
1234567891011121314151617181920212223242526272829303132333435363738394041
2. delayed_workdelayed_work是对于周期性的任务,linux提供的一个封装好的快捷方式
本质是利用定时器和工作队列实现的,功能就是延时执行
delayed_work 结构体: struct delayed_work { struct work_struct work; struct timer_list timer; }; struct work_struct { atomic_long_t data; #define WORK_STRUCT_PENDING 0 #define WORK_STRUCT_FLAG_MASK (3UL) #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }; 123456789101112131415
123456789101112131415
调度:int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
当delay(单位是jiffies)延时后,work成员中的work_func_t 类型成员 func() 会被执行
如果要周期性的执行任务,需要在 delayed_work 的工作函数中再次调用 schedule_delayed_work()
ms 转化成 jiffiesmsecs_to_jiffies();
取消 delayed_work:int cancel_delayed_work(struct delayed_work *work); int cancel_delayed_work_sync(struct delayed_work *work); 12
12
3. 内核延时3.1 短延时:粗略的延时忙等待的形式void ndelay(unsigned long nsecs); –> ns
void udelay(unsigned long usecs); –> us
void mdelay(unsigned long msecs); –> ms
睡眠等待的形式,这样线程放弃对系统资源的占用,解放cpuvoid msleep(unsigned int millisecs); –> 不可被打断
unsigned long msleep_interruptible(unsigned int millisecs); –> 可被打断
void ssleep(unsigned int seconds); –> 不可被打断
3.2 长延时:一个直观的方式是比较当前 jiffies 和目标 jiffies。
time_after()
函数原型:
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) 1234
1234
time_before()
函数原型:
#define time_before(a,b) time_after(b,a) 1
1
一个忙等待先延时 100 个jiffies 再延迟 2s 的实例:
/*延迟 100 个 jiffies*/ unsigned long delay = jiffies + 100; while (time_before(jiffies, delay)); /*再延迟 2s*/ unsigned long delay = jiffies + 2*Hz; while (time_before(jiffies, delay)); 1234567
1234567
3.3 睡着延时:3.1 schedule_timeout() :schedule_timeout_uninterruptible() –> 调用 schedule_timeout()之前置进程状态为 TASK_
INTERRUPTIBLE
schedule_timeout_interruptible() –> 置进程状态为TASK_UNINTERRUPTIBLE
源码:
signed long _ _sched schedule_timeout_interruptible(signed long timeout) { _ _set_current_state(TASK_INTERRUPTIBLE); return schedule_timeout(timeout); } signed long _ _sched schedule_timeout_uninterruptible(signed long timeout) { _ _set_current_state(TASK_UNINTERRUPTIBLE); return schedule_timeout(timeout); } 1234567891011
1234567891011
使用实例:
void msleep(unsigned int msecs) { unsigned long timeout = msecs_to_jiffies(msecs) + 1; while (timeout) timeout = schedule_timeout_uninterruptible(timeout); } unsigned long msleep_interruptible(unsigned int msecs) { unsigned long timeout = msecs_to_jiffies(msecs) + 1; while (timeout && !signal_pending(current)) timeout = schedule_timeout_interruptible(timeout); return jiffies_to_msecs(timeout); } 12345678910111213141516
12345678910111213141516
3.2 sleep_on_timeout功能:
将当前进程添加到等待队列中,在等待队列中睡眠,当超时发生时,进程被唤醒
sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout); –> 不可被打断
interruptible_sleep_on_timeout(wait_queue_head_t*q, unsigned long timeout); –> 可被打断
定时器 |