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