`
mmdev
  • 浏览: 12893071 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

LDD3学习笔记(10):延时和延后

 
阅读更多
1、延后执行

设备驱动常常需要延后一段时间来执行一个特定片段的代码,常常允许硬件完成某个任务。

2、时间管理

#include<linux/param.h>

HZ

HZ符号指定了每秒产生的时钟嘀哒的数目.

#include<linux/jiffies.h>

volatileunsignedlongjiffies;

u64jiffies_64;

jiffies_64变量每个时钟嘀哒时被递增;因此,它是每秒递增HZ.内核代码几乎常常引用

jiffies,它在64-位平台和jiffies_64相同并且在32-位平台是它低有效的一半.

inttime_after(unsignedlonga,unsignedlongb);

inttime_before(unsignedlonga,unsignedlongb);

inttime_after_eq(unsignedlonga,unsignedlongb);

inttime_before_eq(unsignedlonga,unsignedlongb);

这些布尔表达式以一种安全的方式比较jiffies,没有万一计数器溢出的问题和不需要存取

jiffies_64.

u64get_jiffies_64(void);

获取jiffies_64而没有竞争条件.

#include<linux/time.h>

unsignedlongtimespec_to_jiffies(structtimespec*value);

voidjiffies_to_timespec(unsignedlongjiffies,structtimespec*value);

unsignedlongtimeval_to_jiffies(structtimeval*value);

voidjiffies_to_timeval(unsignedlongjiffies,structtimeval*value);

jiffies和其他表示之间转换时间表示.

#include<asm/msr.h>

rdtsc(low32,high32);

rdtscl(low32);

rdtscll(var32);

x86-特定的宏定义来读取时戳计数器.它们作为232-位来读取,只读低一半,或者全部读

到一个longlong变量.

#include<linux/timex.h>

cycles_tget_cycles(void);

以平台独立的方式返回时戳计数器.如果CPU没提供时戳特性,返回0.

#include<linux/time.h>

unsignedlongmktime(year,mon,day,h,m,s);

返回自Epoch以来的秒数,基于6unsignedint参数.

voiddo_gettimeofday(structtimeval*tv);

返回当前时间,作为自Epoch以来的秒数和微秒数,用硬件能提供的最好的精度.在大部分的

平台这个解决方法是一个微秒或者更好,尽管一些平台只提供jiffies精度.

structtimespeccurrent_kernel_time(void);

返回当前时间,以一个jiffy的精度.

3、延迟

#include<linux/wait.h>

longwait_event_interruptible_timeout(wait_queue_head_t*q,condition,signedlongtimeout);

使当前进程在等待队列进入睡眠,安装一个以jiffies表达的超时值.使用schedule_timeout(

)给不可中断睡眠.

#include<linux/sched.h>

signedlongschedule_timeout(signedlongtimeout);

调用调度器,在确保当前进程在超时到的时候被唤醒后.调用者首先必须调用set_curret_state

来使自己进入一个可中断的或者不可中断的睡眠状态.

#include<linux/delay.h>

voidndelay(unsignedlongnsecs);

voidudelay(unsignedlongusecs);

voidmdelay(unsignedlongmsecs);

引入一个整数纳秒,微秒和毫秒的延迟.获得的延迟至少是请求的值,但是可能更多.每个函

数的参数必须不超过一个平台特定的限制(常常是几千).

voidmsleep(unsignedintmillisecs);

unsignedlongmsleep_interruptible(unsignedintmillisecs);

voidssleep(unsignedintseconds);

使进程进入睡眠给定的毫秒数(或者秒,如果使ssleep).

4、内核定时器

#include<asm/hardirq.h>

intin_interrupt(void);

intin_atomic(void);

返回一个布尔值告知是否调用代码在中断上下文或者原子上下文执行.中断上下文是在一

个进程上下文之外,或者在硬件或者软件中断处理中.原子上下文是当你不能调度一个中断

上下文或者一个持有一个自旋锁的进程的上下文.

#include<linux/timer.h>

voidinit_timer(structtimer_list*timer);

structtimer_listTIMER_INITIALIZER(_function,_expires,_data);

这个函数和静态的定时器结构的声明是初始化一个timer_list数据结构的2个方法.

voidadd_timer(structtimer_list*timer);

注册定时器结构来在当前CPU上运行.

intmod_timer(structtimer_list*timer,unsignedlongexpires);

改变一个已经被调度的定时器结构的超时时间.它也能作为一个add_timer的替代.

inttimer_pending(structtimer_list*timer);

宏定义,返回一个布尔值说明是否这个定时器结构已经被注册运行.

voiddel_timer(structtimer_list*timer);

voiddel_timer_sync(structtimer_list*timer);

从激活的定时器链表中去除一个定时器.后者保证这定时器当前没有在另一个CPU上运行.

5、Tacklets机制

#include<linux/interrupt.h>

DECLARE_TASKLET(name,func,data);

DECLARE_TASKLET_DISABLED(name,func,data);

voidtasklet_init(structtasklet_struct*t,void(*func)(unsignedlong),unsignedlongdata);

2个宏定义声明一个tasklet结构,tasklet_init函数初始化一个已经通过分配或其他方式

获得的tasklet结构.2DECLARE宏标识这个tasklet为禁止的.

voidtasklet_disable(structtasklet_struct*t);

voidtasklet_disable_nosync(structtasklet_struct*t);

voidtasklet_enable(structtasklet_struct*t);

禁止和使能一个tasklet.每个禁止必须配对一个使能(你可以禁止这个tasklet即便它已经被

禁止).函数tasklet_disable等待tasklet终止如果它在另一个CPU上运行.这个非同步版本不

采用这个额外的步骤.

voidtasklet_schedule(structtasklet_struct*t);

voidtasklet_hi_schedule(structtasklet_struct*t);

调度一个tasklet运行,或者作为一个"正常"tasklet或者一个高优先级的.当软中断被执行,

优先级tasklets被首先处理,而正常tasklet最后执行.

voidtasklet_kill(structtasklet_struct*t);

从激活的链表中去掉tasklet,如果它被调度执行.如同tasklet_disable,这个函数可能在SMP

统中阻塞等待tasklet终止,如果它当前在另一个CPU上运行.

6、工作队列

#include<linux/workqueue.h>

structworkqueue_struct;

structwork_struct;

这些结构分别表示一个工作队列和一个工作入口.

structworkqueue_struct*create_workqueue(constchar*name);

structworkqueue_struct*create_singlethread_workqueue(constchar*name);

voiddestroy_workqueue(structworkqueue_struct*queue);

创建和销毁工作队列的函数.一个对create_workqueue的调用创建一个有一个工作者线程在

系统中每个处理器上的队列;相反,create_singlethread_workqueue创建一个有一个单个工作

者进程的工作队列.

DECLARE_WORK(name,void(*function)(void*),void*data);

INIT_WORK(structwork_struct*work,void(*function)(void*),void*data);

PREPARE_WORK(structwork_struct*work,void(*function)(void*),void*data);

声明和初始化工作队列入口的宏.

intqueue_work(structworkqueue_struct*queue,structwork_struct*work);

intqueue_delayed_work(structworkqueue_struct*queue,structwork_struct*work,unsignedlongdelay);

从一个工作队列对工作进行排队执行的函数.

intcancel_delayed_work(structwork_struct*work);

voidflush_workqueue(structworkqueue_struct*queue);

使用cancel_delayed_work来从一个工作队列中去除入口;flush_workqueue确保没有工作队列入口在系统中任何地方运行.

intschedule_work(structwork_struct*work);

intschedule_delayed_work(structwork_struct*work,unsignedlongdelay);

voidflush_scheduled_work(void);

使用共享队列的函数.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics