打印

内核定时器和延时

[复制链接]
281|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
冰糖炖雪梨|  楼主 | 2018-8-22 10:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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_work
delayed_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 转化成 jiffies
msecs_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

睡眠等待的形式,这样线程放弃对系统资源的占用,解放cpu
void 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); –> 可被打断






定时器

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

430

主题

436

帖子

0

粉丝