linux 内核中断与时钟的冲突 问题 del_timer,第10章 中断与时钟之内核定时器

10.5 内核定时器

10.5.1 内核定时器编程

TIMER_SOFTIRQ软中断,运行当前处理器CPU上到期的所有定时器。

enum

{

HI_SOFTIRQ=0,

TIMER_SOFTIRQ,

NET_TX_SOFTIRQ,

NET_RX_SOFTIRQ,

BLOCK_SOFTIRQ,

BLOCK_IOPOLL_SOFTIRQ,

TASKLET_SOFTIRQ,

SCHED_SOFTIRQ,

HRTIMER_SOFTIRQ,

NR_SOFTIRQS

};

Linux内核所提供的用于操作定时器的数据结构和函数如下:

1.timer_list

在Linux内核中,timer_list结构体的一个实例对应一个定时器,如代码清单10.9所示。

代码清单10.9 timer_list结构体

#include

struct timer_list {

/*

* All fields that change during normal runtime grouped to the

* same cacheline

*/

struct list_head entry;

unsigned long expires; // 到期时间

struct tvec_base *base;

void (*function)(unsigned long);

unsigned long data;

int slack;

#ifdef CONFIG_TIMER_STATS

int start_pid;

void *start_site;

char start_comm[16];

#endif

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};

function()成员被执行,而data成员则是传入function()函数的参数,expires则是定时器到期的时间(单位:jiffies)。

定义一个名为timer的定时器:

struct timer_list timer;

2.初始化定时器

init_timer是一个宏,

#define init_timer(timer)\

__init_timer((timer), 0)

TIMER_INITIALIZER(_function,_expires,_data)宏用于赋值定时器结构体的function、expires、data和base成员。

#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \

.entry = { .prev = TIMER_ENTRY_STATIC },\

.function = (_function),\

.expires = (_expires),\

.data = (_data),\

.base = (void *)(__TIMER_BASE(_flags)),\

.slack = -1,\

__TIMER_LOCKDEP_MAP_INITIALIZER(\

__FILE__ ":" __stringify(__LINE__))\

}

#define TIMER_INITIALIZER(_function, _expires, _data)\

__TIMER_INITIALIZER((_function), (_expires), (_data), 0)

DEFINE_TIMER(_name,_function,_expires,_data)宏是定义并初始化定时器成员的“快捷方式”,这个宏定义为:

#define DEFINE_TIMER(_name, _function, _expires, _data)\

struct timer_list _name =\

TIMER_INITIALIZER(_function, _expires, _data)

setup_timer()也可用于初始化定时器并赋值其成员,其源代码为:

#define __setup_timer(_timer, _fn, _data, _flags)\

do {\

__init_timer((_timer), (_flags));\

(_timer)->function = (_fn);\

(_timer)->data = (_data);\

} while (0)

#define setup_timer(timer, fn, data)\

__setup_timer((timer), (fn), (data), 0)

3.增加定时器

void add_timer(struct timer_list * timer);

该函数用于注册内核定时器,将定时器加入到内核动态定时器链表中。

4.删除定时器

int del_timer(struct timer_list * timer);

该函数函数用于删除定时器。

del_timer_sync()是del_timer()的同步版,在删除一个定时器时需等待其被处理完,该函数的调用不能发生在中断上下文中。

5.修改定时器的expire(到期时间)

int mod_timer(struct timer_list *timer, unsigned long expires);

该函数用于修改定时器的到期时间,在新的被传入的expires到来后才会执行定时器函数。

该函数的定义在kernel/time/timer.c

/**

int mod_timer(struct timer_list *timer, unsigned long expires)

{

expires = apply_slack(timer, expires);

/*

* This is a common optimization triggered by the

* networking code - if the timer is re-modified

* to be the same thing then just return:

*/

if (timer_pending(timer) && timer->expires == expires)

return 1;

return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);

}

EXPORT_SYMBOL(mod_timer);

代码清单10.10 内核定时器使用模板

/* 定时器处理函数 */static void xxx_do_timer(unsigned long arg){}{

/* 设备结构体指针作为定时器处理函数参数 */

将定时器加入到内核动态定时器链表中

}

/* xxx驱动中的某函数 */

xxx_func2(…)

{

}

此外,Linux内核支持tickless(无滴答)和NO_HZ模式后,内核也包含对hrtimer(高精度定时器)的支持,可以支持到微秒级别的精度。

内核也定义了hrtimer结构体,

/**

timerqueue node, which also manages node.expires,

the absolute expiry time in the hrtimers internal

representation. The time is related to the clock on

which the timer is based. Is setup by adding

slack to the _softexpires value. For non range timers

identical to _softexpires.

The time which was given as expiry time when the timer

was armed.

timer expiry callback function

pointer to the timer base (per cpu and per clock)

state information (See bit values above)

started the timer

timer statistics field to store the site where the timer

was started

started the timer

struct hrtimer {

struct timerqueue_nodenode;

ktime_t_softexpires;

enum hrtimer_restart(*function)(struct hrtimer *);

struct hrtimer_clock_base*base;

unsigned longstate;

#ifdef CONFIG_TIMER_STATS

intstart_pid;

void*start_site;

charstart_comm[16];

#endif

};

hrtimer_set_expires()、hrtimer_start_expires()、hrtimer_forward_now()、hrtimer_restart()等类似的API来完成hrtimer的设置、时间推移以及到期回调。

代码清单10.11内核高精度定时器(hrtimer)使用模板

struct imx_pcm_runtime_data {

......

struct hrtimer hrt; // 内核高精度定时器

......

};

static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)iprtd->poll_time_ns));//把hrtimer的时间前移了iprtd->poll_time_ns纳秒HRTIMER_RESTART;

static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)

{SNDRV_PCM_TRIGGER_START:iprtd->poll_time_ns),

}

static int snd_imx_open(struct snd_pcm_substream *substream)

{

......

hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); /* 初始化高精度定时器 */

iprtd->hrt.function = snd_hrtimer_callback; /* 指定回调函数 */

return 0;

}

static int snd_imx_close(struct snd_pcm_substream *substream)

{

}

10.5.2 内核中延迟的工作delayed_work

对于周期性的任务,除定时器外,在Linux内核中还可利用一套封装得很好的快捷机制,这套快捷机制就是延迟工作delayed_work,其本质利用工作队列和定时器实现。

delayed_work结构体的定义:

struct delayed_work {

};

通过如下函数调度一个delayed_work在指定的延时后执行:

/**

static inline boolschedule_delayed_work(struct delayed_work *dwork,

unsigned longdelay)

{

return queue_delayed_work(system_wq, dwork, delay);

}

当指定的delay到来时,struct delayed_work结构体中的work成员work_func_t类型成员func()会被执行。

work_func_t类型定义为:

typedef void (*work_func_t)(struct work_struct *work); // 函数指针类型

其中,delay参数的单位是jiffies,一种常见的用法如下:

schedule_delayed_work(&work, msecs_to_jiffies(poll_interval));

msecs_to_jiffies()用于将毫秒转化为jiffies。

如果要周期性地执行任务,通常会在delayed_work的工作函数中再次调用schedule_delayed_work(),周而复始。

用来取消delayed_work的函数:

extern bool cancel_delayed_work(struct delayed_work *dwork);

extern bool cancel_delayed_work_sync(struct delayed_work *dwork);

这两个函数定义在kernel/workqueue.c

/**

bool cancel_delayed_work(struct delayed_work *dwork)

{

unsigned long flags;

int ret;

do {

ret = try_to_grab_pending(&dwork->work, true, &flags);

} while (unlikely(ret == -EAGAIN));

if (unlikely(ret < 0))

return false;

set_work_pool_and_clear_pending(&dwork->work,

get_work_pool_id(&dwork->work));

local_irq_restore(flags);

return ret;

}

EXPORT_SYMBOL(cancel_delayed_work);

/**

bool cancel_delayed_work_sync(struct delayed_work *dwork)

{

return __cancel_work_timer(&dwork->work, true);

}

EXPORT_SYMBOL(cancel_delayed_work_sync);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值