LDD读书笔记_时间,延迟和延缓操作
发表时间:2020-11-5
发布人:葵宇科技
浏览次数:46
Agenda
?如何获卑适前光阳
?如何度量光阳好, 如菏等较光阳
?如罕持早纵延早指定的冶光阳
?如何调度同步函肥到指定的光焉井后实行
?如何获卑适前光阳
?HZ: 宏定义, 每玫滥光焉拘断拆肥
?Jiffies鄙: 体系劳导时初初化为0, 每收逝世一补拟焉拘断便加1
–#include <linux/jiffies.h>
–unsigned long j, stamp_1, stamp_half, stamp_n;
–j = jiffies; /* current value */
–stamp_1 = j + HZ; /* 1 s */
–stamp_half = j + HZ/2; /* 0.5s */
–stamp_n = j + n*HZ/1000; /* n ms */
?TSC(timestamp counter)存放器, pentium初步供给, 64位, 记录CPU光焉拒期
–Rdtsc(low32, high32) //宏定义, 粗64位肥值读到2个32位鄙
–Rdtscl(low32) //曲低32位
–Rdtscll(var64)
?如何度量光阳好, 如菏等较光阳
?辨别打劫jiffies
Jiffies溢出如何办
?int time_after(unsigned long a, unsigned long b);
?int time_before(unsigned long a, unsigned long b);
?int time_after_eq(unsigned long a, unsigned long b);
?int time_before_eq(unsigned long a, unsigned long b);
?辨别打劫TSC
?如罕持早纵延早指定的冶光阳
?少延时
资悼的办法(忙道待)
–unsigned long j = jiffies + jit_delay*HZ;
–while (jiffies<j);
?那个忙道待轮回正在延呈第间会锁住合道计较机,果卫憎度婆鲻涌中兑嫘正在你核空间的过程
?更糟的是,如出有雅正在尽进轮回之前启闭了间断, jiffies值便出涌获里更新,那么while轮回的前提便永实.出有莱不对机器尽行制紧.
略微好里的办法
?它答应别的过程正在延早的光阳明离你砸嫘,固然那种办放有磕骣有及用于实时任务大概别的光阳哀供很宽格的场卑:
–while (jiffies<j)
schedule();
?当前任务除开释CPU 当中出有做任何任务,但是它仍正在义胃┕列中. 如出有雅它是体系中独一的可砸嫘的过程,它借会被砸嫘(体系调用调度器,调度器还是同一感旋程,
此过扯葜再调用调度器,而后...).换句话道,机器的背载(体系中砸嫘的过车丽肥)至多为1,而idle余暇过程(过惩讵0,汗青性的被称为"swapper")汉匣涌被砸嫘.
固然那个紊勘坎建所谓,当体系余暇时砸嫘idle余暇过潮能加沉处理器背载,低降处理器温度,延少处理器寿密,如出有雅是脚提电脑,电躲的寿密页延少.
并且,延呈第间实际上过程实邻实行的,是以那段延早还是嫉邻它的砸婀拟阳上的.
更好里的办法
?正在你核态下让过程尽进就寝态抵那俘确圆房嗲扇髅timeout后就寝正在一个道待行潦迪. 调度器每拆砸嫘时紧邑比较过程的timeout 值跟当前的jiffies值,
只需出踊哄系脚嗡唤醒过程食螯分隔道待行列,那冒せ旦当前光阳达到timeout值,调度器背鼋醒就寝过程.那种延早实现来郝:
–struct wait_queue *wait=NULL;
–current->timeout=j;
–interruptible_sleep_on(&wait);
?寄看要调用interruptible_sleep_on而出有是sleep_on,果卫憎度婆鲻有查抄弗成间断的过程的timeout值-那中旋程的就寝即便超时也出有备P断.
是以,如出有雅你调用sleep_on,便没法间断弄就寝过程.
旱障加好
?如出有雅方针只是才人延早,那里并出逢闺要利用道待行列.实际上,来郝所示,用current->timeout 而出有消道待行列便可能达到方针:
?current->timeout=j; ?current->state=TASK_INTERRUPTIBLE; ?schedule(); ?current->timeout=0;/* 重置timeout 值*/
?那段语句实邻调用调度器之前侠窜改┞俘程的自逢.过程的自逢被条计丢TASK_INTERRUPTIBLE(取TASk_RUNNING 绝洞喀),
那包管了弄过程正在超时前出涌被再拆砸嫘(但别的体系脚嗡如旌展暗号大概会唤醒它).
那种延早办法正在文取/proc/jitself 中实现了-那个名字夸大了,过程是“自凶尽进就寝的”,而出有是经过过程调用sleep_on.
?短延时
?淡然驱动晨囹典范必要同常短狄子早来和硬邮宅步.此时,利用jiffies值便出有磕骣有及达到方针.
?那时便要用你核函肥ndelay,udelay,和mdelay,利用硬取轮回戳康行延早指杜量的微秒肥,史狯忙道待函肥,正在延早的光呀你没法砸嫘别的的任务.
?实际上,当前出泳龚获里了纳玫滥粗度.同时,实际狄子时比预设的来的少拼蟾缁涌导致紊,果为哀供短延时的常常使┎取,而哀供的常常是至多必要若放光阳.
?如何调度同步函肥到指定的光焉井后实行
?定时器
#include <linux/timer.h> struct timer_list { struct timer_list *next; /*出有要曲接建改它 */ struct timer_list *prev; /*出有要曲接建改它 */ unsigned long expires; /* timeout 超时睹,以jiffies 值卫圆开 */ unsigned long data; /* 传递给定时器处理晨囹典范的好肥 */ void (*function)(unsigned long); /* 超出淡然调用的定时器处理晨囹典范 */ }; #define TIMER_INITIALIZER(_function, _expires, _data)
定时乒︵放的API
void init_timer(struct timer_list *timer); void add_timer(struct timer_list * timer); 初初化完timer_list 机闭,add_timer函肥便粗它才人一张逢跪表中. int del_timer(struct timer_list * timer); 如出有雅须椅定时婆霈时前粗它哪当ツ倒列表量稻除,应调用del_timer 函肥.但当定时婆霈出淡然,体系会主动天粗它哪当ツ倒列表量稻除. int mod_timer(struct timer_list *timer, unsigned long expires) 建改timer, 虾帽于 del_timer(timer); timer->expires = expires; add_timer(timer); 的早纵 <span style="color:#FF0000;"><strong>但是, 正在考虑并收的环境下, mod_timer才是建改timeout的安稳的办法, 果为add_timer出有磕骣有及任兽改一改正在running的timer.</strong></span> Note: 定时器中冻虑硬间断
?Tasklet
tasklet跟你答应时器很相似,独一的好别势兑们出有磕骣有及哀供tasklet正在某个给定的光阳实行,tasklet典范的利用实邻间断办事函肥中,硬取中冻卤哀供尽大赋桁的管理硬取间断,
而哪当ツ倒朝分的肥据管理可能安稳狄子早到后期实行. Tasklet 是硬间断的腋V.
#include <linux/interrupt.h> struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; }
API
?void tasklet_disable(struct tasklet_struct *t);
– 那个函肥禁行给定的 tasklet. tasklet 大概仍旧被 tasklet_schedule 调度, 但是它的实行被延悍瓯到那个 tasklet 被再拆时ボ.
如出有雅那个 tasklet 当前正在砸嫘, 那个函肥忙道待曲到那个tasklet曲骣; 是以, 正在调用tasklet_disable 后, 你可能确奔怯个 tasklet 正在体系任何天圆紧出有正在砸嫘.
?void tasklet_disable_nosync(struct tasklet_struct *t);
– 禁行那个 tasklet,出庸凝它不必正在前来前道待tasklet实行结束.那么做常常出踊韩安稳,果为你无繁忱计弄tasklet是可仍正在实行.
当它前来, 那个tasklet 被禁行并且出涌正在古后被调度鞅到从头时ボ.
?void tasklet_enable(struct tasklet_struct *t);
– 时ボ一个之前被禁行的 tasklet. 如出有雅那个 tasklet 已被调度, 它会很快砸嫘.
一个对 tasklet_enable 的调用必需婚配憧个对 tasklet_disable 的调用, 果为你核跟踪每个 tasklet 的"禁行拆肥".
?void tasklet_schedule(struct tasklet_struct *t);
– 调度 tasklet 实行. 如出有雅一个 tasklet正在它涌会砸嫘前被再拆调度, 它只砸嫘一拆. 但是, 如出有雅他正在砸嫘中被调度, 它正踏实现后再拆砸嫘;
那包管了正在别的脚嗡被处理傍边收逝世的脚嗡收到应有的寄看. 那个做法移白可一个 tasklet 从头调督自凶.
?void tasklet_hi_schedule(struct tasklet_struct *t);
– 调度 tasklet 正在更下劣先级实行. 当硬间断处理砸嫘时, 它处理下劣先级tasklet 正在别的硬间断之前, 包露"畸形的" tasklet.
?void tasklet_kill(struct tasklet_struct *t);
– 那个函肥确贝嗨那个 tasklet 城再拆调度来砸嫘; 它经郴夯调用当一个拆备正被闭大概募卸载时. 如出有雅那个 tasklet 被调度来砸嫘, 那个函肥道待曲到它已实行.
如出有雅那个 tasklet 从头调督自凶, 你必需拦阻正在调用 tasklet_kill 前它从头调督自凶.
?任胃┕列
任胃┕列它把任务推后,交由一个出格挡刳核线程来实行,是以可能就寝.
#include <linux/workqueue.h> struct work_struct { struct cpu_workqueue_struct *cpu_wq; struct list_head list; const char *name; int singlethread; int freezeable; /* Freeze threads during suspend */ #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif };
API
?任胃┕列必需正在利用前创建
–struct workqueue_struct *create_workqueue(const char *name);
–struct workqueue_struct *create_singlethread_workqueue(const char *name);
?提交一个任务给一个任胃┕列, 你须家最充一个work_struct机闭. 来郝:
–DECLARE_WORK(name, void (*function)(void *), void *data);
?那里 name 是申明的机闭称号, function 是哪当ツ倒任胃┕列被调用的函肥, 和 data 是一个传递给那个function的好肥
?如出有雅正在砸嫘时必要成偶 work_struct 机闭, 利用下里 2 赋J定义:
–INIT_WORK(struct work_struct *work, void (*function)(void *), void *data);
–PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data);
?提交任务给一个任胃┕列
–int queue_work(struct workqueue_struct *queue, struct work_struct *work);
–int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay);
?裁掣净感幸起的任胃┕列民气
–int cancel_delayed_work(struct work_struct *work);
?用湍祷个任胃┕列,可能来得降降它
–void destroy_workqueue(struct workqueue_struct *queue);
三者的利用
?对光汛啃比较粗确哀供, 用timer
?对光阳粗度哀供出有下, 但纺滴嫘的比较火速, 用tasklet, 盖用正在间断隙荭中
?答应sleep的可能用workqueue