《Linux裝置驅動開發詳解》 核心延時

2021-06-22 10:59:17 字數 2934 閱讀 5166

10.6.1  短延遲

linux 核心中提供了如下 3 個函式分別進行納秒、微秒和毫秒延遲。

void ndelay(unsigned long nsecs); 

void udelay(unsigned long usecs); 

void mdelay(unsigned long msecs); 

上述延遲的實現原理本質上是忙等待, 它根據 cpu 頻率進行一定次數的迴圈。 有時候,可以在軟體中進行這樣的延遲:

void delay(unsigned int time) 

ndelay()、udelay()和 mdelay()函式的實現方式機理與此類似。

毫秒時延(以及更大的秒時延)已經比較大了,在核心中,最好不要直接使用mdelay()函式,這將無謂地耗費 cpu 資源,對於毫秒級以上時延,核心提供了下述函式:

void msleep(unsigned int millisecs); 

unsigned long msleep_interruptible(unsigned int millisecs); 

void ssleep(unsigned int seconds); 

上述函式將使得呼叫它的程序睡眠引數指定的時間,msleep()、ssleep()不能被打斷,而 msleep_interruptible()則可以被打斷。

note:受系統 hz 以及程序排程的影響,msleep()類似函式的精度是有限的。

10.6.2  長延遲

核心中進行延遲的乙個很直觀的方法是比較當前的 jiffies 和目標 jiffies (設定為當前 jiffies 加上時間間隔的 jiffies) ,直到未來的 jiffies 達到目標 jiffies。**清單 10.13給出了使用忙等待先延遲 100 個 jiffies 再延遲 2s 的例項。

**清單 10.13  忙等待時延例項

/*延遲 100 個 jiffies*/ 

unsigned long delay = jiffies + 100;

while (time_before(jiffies, delay));

/*再延遲 2s*/

unsigned long delay = jiffies + 2*hz;

while (time_before(jiffies, delay));

與 time_before()對應的還有乙個 time_after(),它們在核心中定義為(實際上只是將傳入的未來時間 jiffies 和被呼叫時的 jiffies 進行乙個簡單的比較) :

#define time_after(a,b)        \ 

(typecheck(unsigned long, a) &&  \ 

typecheck(unsigned long, b) &&  \ 

((long)(b) - (long)(a) < 0)) 

#define time_before(a,b)  time_after(b,a) 

為了防止 time_before()和 time_after()的比較過程中編譯器對 jiffies 的優化,核心將其定義為 volatile 變數,這將保證它每次都被重新讀取。

10.6.3  睡著延遲

睡著延遲無疑是比忙等待更好的方式,隨著延遲在等待的時間到來之間程序處於睡眠狀態,cpu 資源被其他程序使用。schedule_timeout()可以使當前任務睡眠指定的jiffies 之後重新被排程執行,msleep()和 msleep_interruptible()在本質上都是依靠包含了schedule_timeout() 的 schedule_  timeout_uninterruptible() 和schedule_timeout_interruptible()實現的,如**清單 10.14 所示。

**清單 10.14  schedule_timeout()的使用

void msleep(unsigned int msecs) 

unsigned long msleep_interruptible(unsigned int msecs)

實際上,schedule_timeout()的實現原理是向系統新增乙個定時器,在定時器處理函式中喚醒引數對應的程序。

**清單 10.14 第 6 行和第 14 行分別呼叫 schedule_timeout_uninterruptible()和schedule_timeout_interruptible() , 這兩個函式的區別在於前者在呼叫schedule_timeout()之前置程序狀態為 task_interruptible,後者置程序狀態為task_uninterruptible,如**清單10.15 所示

**清單 10.15  schedule_timeout_interruptible()和schedule_timeout_uninterruptible() 

signed  long  _  _sched  schedule_timeout_interruptible(signed  long timeout) 

signed long _ _sched schedule_timeout_uninterruptible(signed long timeout)

另外,下面兩個函式可以將當前程序新增到等待佇列中, 從而在等待佇列上睡眠。當超時發生時,程序將被喚醒(後者可以在超時前被打斷) ,如下所示:

sleep_on_timeout(wait_queue_head_t*q,

unsigned

long

timeout);

interruptible_sleep_on_timeout(wait_queue_head_t*q,

unsigned

long

timeout);

Linux裝置驅動 核心開發

linux裝置驅動需要使用核心api來實現,一般被包含在linux核心原始碼樹中。驅動可以編譯到核心,隨著核心一起在系統啟動的時候被載入。也可以編譯成核心模組,在系統執行起來之後動態地載入到核心中,使得除錯的時候無需重新編譯核心,也無需重啟系統,很大程度上方便了驅動 的除錯。但並不是只有裝置驅動才能...

linux裝置驅動開發詳解

第四章 linux核心模組 1.linux核心模組的優點 1 模組可以不用編譯linux核心,在開發除錯的時候,通過動態載入命令載入進核心就可以執行,大大提公升了開發除錯效率,同時也控制了linux核心的大小 2 模組一旦被載入,它就和linux核心其他的部分一樣,直接執行。2.linux核心模組基...

《Linux裝置驅動開發詳解》 核心定時器

10.5.1 核心定時器程式設計 軟體意義上的定時器最終依賴硬體定時器來實現,核心在時鐘中斷發生後檢測各定時器是否到期,到期後的定時器處理函式將作為軟中斷在底半部執行。實質上,時鐘中斷處理程式執行 update process timers 函式,該函式呼叫run local timers 函式,這...