我是靠谱客的博主 漂亮钢笔,这篇文章主要介绍内核定时器和延时1. 内核定时器:2. delayed_work3. 内核延时,现在分享给大家,希望可以做个参考。

1. 内核定时器:

内核在时钟中断发生后检测各定时器是否到期,在linux内核中提供了一组函数和数据结构来完成定时触发工作/周期的事务。

timer_list 结构体: – 表示一个定时器


复制代码
1
2
3
4
5
6
7
8
struct timer_list { struct list_head entry; /* 定时器列表 */ unsigned long expires; /*定时器到期时间*/ void (*function)(unsigned long); /* 定时器处理函数指针 */ unsigned long data; /* 作为参数被传入定时器处理函数 */ struct timer_base_s *base; ... };

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 成员
函数原型是

复制代码
1
2
3
4
5
6
7
#define TIMER_INITIALIZER(_function, _expires, _data) { .entry = { .prev = TIMER_ENTRY_STATIC }, .function = (_function), .expires = (_expires), .data = (_data), .base = &boot_tvec_bases, }

3.DEFINE_TIMER(_name, _function, _expires, _data)
一个给结构体赋值的快捷方式,
函数原型是:

复制代码
1
2
3
#define DEFINE_TIMER(_name, _function, _expires, _data) struct timer_list _name = TIMER_INITIALIZER(_function, _expires, _data)

4.static inline void
setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data)

这个函数也可以给 定时器 结构体成员赋值,
函数原型是:

复制代码
1
2
3
4
5
6
7
8
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); }

增加定时器:


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);
这个函数有启动定时器的功能

使用思路:


  1. open 函数中setup_timer,想要用定时器的地方mod_timer.
  2. 定义 timer_list 结构体,在想要调用的地方填充上 timer_list里边的成员,init_timer,add_timer

注意事项:


  1. 定时器的每次添加之后,执行完定时器后就会失效,要想循环使用,需要在定时函数中添加
  2. del_timer 是删除没有发生的定时器,如果已经发生了,删除不删除应该无所谓

使用模板:


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*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); ... }

2. delayed_work

delayed_work是对于周期性的任务,linux提供的一个封装好的快捷方式
本质是利用定时器和工作队列实现的,功能就是延时执行

delayed_work 结构体:


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 };

调度:


int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
当delay(单位是jiffies)延时后,work成员中的work_func_t 类型成员 func() 会被执行
如果要周期性的执行任务,需要在 delayed_work 的工作函数中再次调用 schedule_delayed_work()

ms 转化成 jiffies


msecs_to_jiffies(const unsigned int m);

取消 delayed_work:


复制代码
1
2
int cancel_delayed_work(struct delayed_work *work); int cancel_delayed_work_sync(struct delayed_work *work);

3. 内核延时

3.1 短延时:粗略的延时


忙等待的形式

void ndelay(unsigned long nsecs); –> ns
void udelay(unsigned long usecs); –> us
void mdelay(unsigned long msecs); –> ms

睡眠等待的形式,这样线程放弃对系统资源的占用,解放cpu

void msleep(unsigned int millisecs); –> 不可被打断
unsigned long msleep_interruptible(unsigned int millisecs); –> 可被打断
void ssleep(unsigned int seconds); –> 不可被打断

3.2 长延时:


一个直观的方式是比较当前 jiffies 和目标 jiffies。
time_after()

函数原型:

复制代码
1
2
3
4
#define time_after(a,b) (typecheck(unsigned long, a) && typecheck(unsigned long, b) && ((long)(b) - (long)(a) < 0))

time_before()
函数原型:

复制代码
1
#define time_before(a,b) time_after(b,a)

一个忙等待先延时 100 个jiffies 再延迟 2s 的实例:

复制代码
1
2
3
4
5
6
7
/*延迟 100 个 jiffies*/ unsigned long delay = jiffies + 100; while (time_before(jiffies, delay)); /*再延迟 2s*/ unsigned long delay = jiffies + 2*Hz; while (time_before(jiffies, delay));

3.3 睡着延时:


3.1 schedule_timeout() :

schedule_timeout_uninterruptible() –> 调用 schedule_timeout()之前置进程状态为 TASK_
INTERRUPTIBLE
schedule_timeout_interruptible() –> 置进程状态为TASK_UNINTERRUPTIBLE
源码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
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); }

使用实例:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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); }

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); –> 可被打断

最后

以上就是漂亮钢笔最近收集整理的关于内核定时器和延时1. 内核定时器:2. delayed_work3. 内核延时的全部内容,更多相关内核定时器和延时1.内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部