Linux內核驅動之延時---內核超時處理【轉】


內核超時處理
jiffies 計數器
定時器中斷由系統定時硬件以規律地間隔產生; 這個間隔在啟動時由內核根據 HZ 值來編程, HZ 是一個體系依賴的值, 每次發生一個時鍾中斷, 一個內核計數器的值遞增. 這個計數器在系統啟動時初始化為 0, 因此它代表從最后一次啟動以來的時鍾嘀噠的數目.

這個計數器和來讀取它的實用函數位於 , 盡管你會常常只是包含 ,

#include
unsigned long j, stamp_1, stamp_half, stamp_n;
 
j = jiffies; /* read the current value */
stamp_1 = j + HZ; /* 1 second in the future */
stamp_half = j + HZ/2; /* half a second */
stamp_n = j + n * HZ / 1000; /* n milliseconds */

 

忙等待

如果你想延時執行多個時鍾嘀噠, 允許在值中某些疏忽, 最容易的( 盡管不推薦 ) 的實現是一個監視 jiffy 計數器的循環. 這種忙等待實現常常看來象下面的代碼, 這里 j1 是 jiffies 的在延時超時的值:

while (time_before(jiffies, j1)){}

 
超時
    到目前為止所展示的次優化的延時循環通過查看 jiffy 計數器而不告訴任何人來工作. 但是最好的實現一個延時的方法, 如你可能猜想的, 常常是請求內核為你做. 有 2 種方法來建立一個基於 jiffy 的超時, 依賴於是否你的驅動在等待其他的事件.

如果你的驅動使用一個等待隊列來等待某些其他事件, 但是你也想確保它在一個確定時間段內運行, 可以使用 wait_event_timeout 或者wait_event_interruptible_timeout:

#include
long wait_event_timeout(wait_queue_head_t q, condition, long timeout);
long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout);

這些函數在給定隊列上睡眠, 但是它們在超時(以 jiffies 表示)到后返回. 因此, 它們實現一個限定的睡眠不會一直睡下去. 注意超時值表示要等待的jiffies 數, 不是一個絕對時間值. 這個值由一個有符號的數表示, 因為它有時是一個相減運算的結果, 盡管這些函數如果提供的超時值是負值通過一個printk 語句抱怨. 如果超時到, 這些函數返回 0; 如果這個進程被其他事件喚醒, 它返回以 jiffies 表示的剩余超時值. 返回值從不會是負值, 甚至如果延時由於系統負載而比期望的值大.

wait_event_timeout 和 wait_event_interruptible_timeout 被設計為有硬件驅動存在, 這里可以用任何一種方法來恢復執行: 或者有人調用 wake_up 在等待隊列上, 或者超時到. 這不適用於 jitqueue, 因為沒人在等待隊列上調用 wake_up ( 畢竟, 沒有其他代碼知道它 ), 因此這個進程當超時到時一直喚醒. 為適應這個特別的情況, 這里你想延后執行不等待特定事件, 內核提供了 schedule_timeout 函數, 因此你可以避免聲明和使用一個多余的等待隊列頭:

#include
signed long schedule_timeout(signed long timeout);

這里, timeout 是要延時的 jiffies 數. 返回值是 0 除非這個函數在給定的 timeout 流失前返回(響應一個信號). schedule_timeout 請求調用者首先設置當前的進程狀態, 因此一個典型調用看來如此:

set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout (delay);

第一行調用 set_current_state 來設定一些東西以便調度器不會再次運行當前進程, 直到超時將它置回 TASK_RUNNING 狀態. 為獲得一個不可中斷的延時, 使用 TASK_UNINTERRUPTIBLE 代替.

短延時

當一個設備驅動需要處理它的硬件的反應時間, 涉及到的延時常常是最多幾個毫秒.

內核函數 ndelay, udelay, 以及 mdelay 對於短延時好用, 分別延后執行指定的納秒數, 微秒數或者毫秒數. 它們的原型是:

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

有另一個方法獲得毫秒(和更長)延時而不用涉及到忙等待. 文件 聲明這些函數:

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

前 2 個函數使調用進程進入睡眠給定的毫秒數. 一個對 msleep 的調用是不可中斷的; 你能確保進程睡眠至少給定的毫秒數. 如果你的驅動位於一個等待隊列並且你想喚醒來打斷睡眠, 使用 msleep_interruptible. 從 msleep_interruptible 的返回值正常地是 0; 如果, 但是, 這個進程被提早喚醒, 返回值是在初始請求睡眠周期中剩余的毫秒數. 對 ssleep 的調用使進程進入一個不可中斷的睡眠給定的秒數.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM