linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)
晚上7點(diǎn)10分..
“小濤哥,這章不是叫Linux設(shè)備驅(qū)動(dòng)程序之中斷與時(shí)鐘,前邊你講了中斷,還給了我很多模版,我都看懂了,這次是不是要開始講時(shí)鐘了..”
“真聰明,越來(lái)越喜歡你這聰明的樣子了,說(shuō)的不錯(cuò),今天就要開始一個(gè)新的模塊--內(nèi)核時(shí)鐘”我很少夸人,為啥今天夸她呢了,呵呵.
定時(shí)器,意思大家都明白,我就不說(shuō)了,要是不明白,把它想成個(gè)鬧鐘總可以吧..
定時(shí)器分為硬件和軟件定時(shí)器,軟件定時(shí)器最終還是要依靠硬件定時(shí)器來(lái)完成。內(nèi)核在時(shí)鐘中斷發(fā)生后檢測(cè)各定時(shí)器是否到期,到期后的定時(shí)器處理函數(shù)將作為軟中斷在底半部執(zhí)行。實(shí)質(zhì)上,時(shí)鐘中斷處理程序執(zhí)行update_process_timers函數(shù),該函數(shù)調(diào)用run_local_timers函數(shù),這個(gè)函數(shù)處理TIMER_SOFTIRQ軟中斷,運(yùn)行當(dāng)前處理上到期的所有定時(shí)器。
Linux內(nèi)核中定義提供了一些用于操作定時(shí)器的數(shù)據(jù)結(jié)構(gòu)和函數(shù)如下:
1)timer_list:說(shuō)定時(shí)器,當(dāng)然要來(lái)個(gè)定時(shí)器的結(jié)構(gòu)體struct timer_list{
struct list_head entry; //定時(shí)器列表
unsigned long expires; //定時(shí)器到期時(shí)間
void (*function)(unsigned long) ;//定時(shí)器處理函數(shù)
unsigned long data; //作為參數(shù)被傳入定時(shí)器處理函數(shù)
struct timer_base_s *base;
}2)初始化定時(shí)器:void init_timer(struct timer_list *timer);經(jīng)過(guò)這個(gè)初始化后,entry的next為NULL,并給base賦值
3)增加定時(shí)器:void add_timer(struct timer_list *timer); 該函數(shù)用于注冊(cè)內(nèi)核定時(shí)器,并將定時(shí)器加入到內(nèi)核動(dòng)態(tài)定時(shí)器鏈表中。4)刪除定時(shí)器:int del_timer(struct timer_list *timer);說(shuō)明:del_timer_sync是del_timer的同步版,主要在多處理器系統(tǒng)中使用,如果編譯內(nèi)核時(shí)不支持SMP,del_timer_sync和del_timer等價(jià).5)修改定時(shí)器:int mod_timer(struct timer_list *timer, unsigned long expires);下邊是一個(gè)使用定時(shí)器的模版:
struct xxx_dev /*second設(shè)備結(jié)構(gòu)體*/
{
struct cdev cdev; /*cdev結(jié)構(gòu)體*/
...
struct timer_list xxx_timer; /*設(shè)備要使用的定時(shí)器*/
};
int xxx_func1(...) //xxx驅(qū)動(dòng)中某函數(shù)
{
struct xxx_dev *dev = filp->private_data;
...
/*初始化定時(shí)器*/
init_timer(&dev->xxx_timer);
dev->xxx_timer.function = &xxx_do_handle;
dev->xxx_timer.data = (unsigned long)dev;
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer); /*添加(注冊(cè))定時(shí)器*/
...
return 0;
}
int xxx_func2(...) //驅(qū)動(dòng)中某函數(shù)
{
...
del_timer(&second_devp->s_timer);
...
}
static void xxx_do_timer(unsigned long arg) //定時(shí)器處理函數(shù)
{
struct xxx_device *dev = (struct xxx_device *)(arg);
...
//調(diào)度定時(shí)器再執(zhí)行
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer);
}
在定時(shí)器函數(shù)中往往會(huì)在做完具體工作后,延遲expires并將定時(shí)器再次添加到內(nèi)核定時(shí)器鏈表中,以便定時(shí)器能被再次觸發(fā)(這句話我也是從別處抄來(lái)的,別告訴小王哈)。
在內(nèi)核定時(shí)器中,常常少不了要說(shuō)下內(nèi)核延遲的事,請(qǐng)接著往下看:
1)短延遲:在linux內(nèi)核中提供了三個(gè)函數(shù)來(lái)分別實(shí)現(xiàn)納秒,微秒,毫秒延遲,原理上是忙等待,它根據(jù)CPU頻率進(jìn)行一定次數(shù)的循環(huán)
void ndelay(unsigned long nsecs);?????????????????? void udelay(unsigned long usecs);???????????????? void mdelay(unsigned long msecs);
毫秒延遲已經(jīng)相當(dāng)大了,當(dāng)然更秒延遲當(dāng)然要小一些,在內(nèi)核中,為了性能,最好不要用mdelay,這會(huì)耗費(fèi)大量cpu資源,那么咋辦呢,涼拌..
void msleep(unsigned int millisecs);?? unsigned long msleep_interruptible(unsigned int millisecs);?? void ssleep(unsigned int seconds);
這三個(gè)是內(nèi)核專門提供該我們用來(lái)處理毫秒以上的延遲。上述函數(shù)將使得調(diào)用它的進(jìn)程睡眠參數(shù)指定的秒數(shù),其中第二個(gè)是可以被打斷的,其余的兩個(gè)是不可以的。
2)長(zhǎng)延遲:內(nèi)核中進(jìn)行延遲最常用的方法就是比較當(dāng)前的jiffies和目標(biāo)jiffies(當(dāng)前的加上時(shí)間間隔的jiffies),直到未來(lái)的jiffies達(dá)到目標(biāo)jiffies。比如:
unsigned long delay = jiffies + 100; //延遲100個(gè)jiffies
while(time_before(jiffies, delay));
與time_before對(duì)應(yīng)的還有一個(gè)time_after().其實(shí)就是#define time_before(a,b)? time_after(b,a);
另外兩個(gè)是time_after_eq(a,b)和time_before_eq(a,b)
3)睡著延遲:這顯然是比忙等待好的方法,因?yàn)樵谖吹絹?lái)之前,進(jìn)程會(huì)處于睡眠狀態(tài),把CPU空出來(lái),讓CPU可以做別的事情,等時(shí)間到了,調(diào)用schedule_timeout()就可以喚醒它并重新調(diào)度執(zhí)行。msleep和msleep_interruptible本質(zhì)上都是依靠包含了schedule_timeout的schedule_timeout_uninterruptible()和schedule_
timeout_interruptible()實(shí)現(xiàn)。就像下邊這樣: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);
}
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);
}
另外還有如下:
time_on_timeout(wait_queue_head_t *q, unsigned long? timeout);
interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);
這兩個(gè)將當(dāng)前進(jìn)程添加到等待隊(duì)列,從而在等待隊(duì)列上睡眠,當(dāng)超時(shí)發(fā)生時(shí),進(jìn)程將被喚醒。
“小王,有關(guān)中斷和系統(tǒng)時(shí)鐘的咱們也講完了,下次就給你來(lái)一個(gè)有關(guān)系統(tǒng)時(shí)鐘的設(shè)備驅(qū)動(dòng)例子,鞏固一下吧,你可要抓緊哦..“
總結(jié)
以上是生活随笔為你收集整理的linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux vim python配置文件
- 下一篇: linux系统下载经验,linux系统的