Linux核心開發之中斷與時鐘 三

2021-06-22 08:26:45 字數 3066 閱讀 3871

晚上7點10分..

「小濤哥,這章不是叫linux裝置驅動程式之中斷與時鐘,前邊你講了中斷,還給了我很多模版,我都看懂了,這次是不是要開始講時鐘了..」

「真聰明,越來越喜歡你這聰明的樣子了,說的不錯,今天就要開始乙個新的模組--核心時鐘」我很少誇人,為啥今天誇她呢了,呵呵.

定時器,意思大家都明白,我就不說了,要是不明白,把它想成個鬧鐘總可以吧..

定時器分為硬體和軟體定時器,軟體定時器最終還是要依靠硬體定時器來完成。核心在時鐘中斷發生後檢測各定時器是否到期,到期後的定時器處理函式將作為軟中斷在底半部執行。實質上,時鐘中斷處理程式執行update_process_timers函式,該函式呼叫run_local_timers函式,這個函式處理timer_softirq軟中斷,執行當前處理上到期的所有定時器。

linux核心中定義提供了一些用於操作定時器的資料結構和函式如下:

1)timer_list:說定時器,當然要來個定時器的結構體

struct timer_list
2)初始化定時器:void init_timer(struct timer_list *timer);經過這個初始化後,entry的next為null,並給base賦值

3)增加定時器:void add_timer(struct timer_list *timer); 該函式用於註冊核心定時器,並將定時器加入到核心動態定時器鍊錶中。

4)刪除定時器:int del_timer(struct timer_list *timer);

說明:del_timer_sync是del_timer的同步版,主要在多處理器系統中使用,如果編譯核心時不支援smp,del_timer_sync和del_timer等價.

5)修改定時器:int mod_timer(struct timer_list *timer, unsigned long expires);
下邊是乙個使用定時器的模版:
struct ***_dev  /*second裝置結構體*/ 

;int ***_func1(...) //***驅動中某函式

int ***_func2(...) //驅動中某函式

static

void ***_do_timer(unsigned

long arg) //定時器處理函式

在定時器函式中往往會在做完具體工作後,延遲expires並將定時器再次新增到核心定時器鍊錶中,以便定時器能被再次觸發(這句話我也是從別處抄來的,別告訴小王哈)。

在核心定時器中,常常少不了要說下核心延遲的事,請接著往下看:

1)短延遲:

在linux核心中提供了三個函式來分別實現納秒,微秒,毫秒延遲,原理上是忙等待,它根據cpu頻率進行一定次數的迴圈

void ndelay(unsigned long nsecs);                   void udelay(unsigned long usecs);                 void mdelay(unsigned long msecs);

毫秒延遲已經相當大了,當然更秒延遲當然要小一些,在核心中,為了效能,最好不要用mdelay,這會耗費大量cpu資源,那麼咋辦呢,涼拌..

void msleep(unsigned int millisecs);   unsigned long msleep_interruptible(unsigned int millisecs);   void ssleep(unsigned int seconds);

這三個是核心專門提供該我們用來處理毫秒以上的延遲。上述函式將使得呼叫它的程序睡眠引數指定的秒數,其中第二個是可以被打斷的,其餘的兩個是不可以的。

2)長延遲:

核心中進行延遲最常用的方法就是比較當前的jiffies和目標jiffies(當前的加上時間間隔的jiffies),直到未來的jiffies達到目標jiffies。比如:

unsigned

long delay = jiffies + 100; //延遲100個jiffies

while(time_before(jiffies, delay));

與time_before對應的還有乙個time_after().其實就是#define time_before(a,b)  time_after(b,a);

另外兩個是time_after_eq(a,b)和time_before_eq(a,b)

3)睡著延遲:這顯然是比忙等待好的方法,因為在未到來之前,程序會處於睡眠狀態,把cpu空出來,讓cpu可以做別的事情,等時間到了,呼叫schedule_timeout()就可以喚醒它並重新排程執行。msleep和msleep_interruptible本質上都是依靠包含了schedule_timeout的schedule_timeout_uninterruptible()和schedule_

timeout_interruptible()實現。就像下邊這樣:

void msleep(unsigned

int msecs)

unsigned

long msleep_interruptible(unsigned

int msecs)

signed

long __sched schedule_timeout_interruptible()signed

long timeout)

signed

long __sched schedule_timeout_uninterruptible()signed

long timeout)

另外還有如下:

time_on_timeout(wait_queue_head_t *q, unsigned long  timeout);

interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

這兩個將當前程序新增到等待佇列,從而在等待佇列上睡眠,當超時發生時,程序將被喚醒。

「小王,有關中斷和系統時鐘的咱們也講完了,下次就給你來乙個有關系統時鐘的裝置驅動例子,鞏固一下吧,你可要抓緊哦..「

Linux核心開發之中斷處理

一 概念 1 外設的處理速度一般慢於cpu。2 cpu不能一直等待外部事件。所以裝置必須有一種方法來通知cpu它的工作進度,這種方法就是中斷。二 中斷實現 在linux驅動程式中,為裝置實現乙個中斷包含兩個步驟 1 向核心註冊中斷 2 實現中斷處理函式 三 中斷處理子系統 1 根據中斷號找到正確的中...

Linux核心 之 中斷

中斷處理函式所作的第一件事情是什麼?答案是遮蔽中斷,所以要遮蔽中斷,是因為新的中斷會再次呼叫中斷處理函式,導致原來中斷處理現場的破壞。因為中斷,它是把原來的上下文都存起來,如果是多級中斷的話,它需要存多級的上下文,除非linux能存多級上下文,感覺是能多存的。如果只能存一級,那必然是要遮蔽中斷,不然...

Linux核心原始碼閱讀之中斷(簡)

本文對linux2.4.0中中斷機制從原始碼層面進行簡要介紹,閱讀需要有一定基礎,詳細版本請參考這裡。這裡主要介紹以下幾個部分 主要是設定中斷向量表中中斷服務的型別,服務程式的入口位址,dpl等。1.1 trap init 初始化系統保留的中斷向量,從0x00到0x1f共36個 init irq 初...