摘要:Linux內(nèi)核或驅(qū)動程序中經(jīng)常會使用到一些延時函數(shù)聚蝶,在這段時間里硬件設(shè)備可以完成相關(guān)的工作杰妓。本文主要講述linux中經(jīng)常使用到的納秒級、毫秒級及秒級的延時函數(shù)及其使用方法和場景碘勉。
1巷挥、時間度量
先介紹兩個有用的全局變量:HZ
和jiffies
- HZ是Linux內(nèi)核中的一個重要全局變量,表示系統(tǒng)在1秒鐘的時間里系統(tǒng)時鐘中斷(由硬件定時器產(chǎn)生)發(fā)生的次數(shù)验靡。它一般取值為1000倍宾,但不同硬件平臺有不同取值雏节。
- 系統(tǒng)初始化的時候,將一個全局計數(shù)器jiffies設(shè)置為0高职,此后每當(dāng)時鐘中斷發(fā)生一次矾屯,系統(tǒng)就將jiffies的值加1,所以這個值記錄了系統(tǒng)啟動以來經(jīng)歷的時間初厚。
- 比較jiffies的值可以使用Linux定義的幾個宏:
/* 當(dāng)a>b時返回true件蚕,否則返回false*/
#define time_after(a,b) ( typecheck(unsigned long,a) &&\
typecheck(unsigned long,a) &&\
((long)(b)-(long)(a) < 0) )
/* 當(dāng)a<b時返回true,否則返回false*/
#define time_before(a,b) time_after(b,a)
/* 當(dāng)a>=b時返回true产禾,否則返回false*/
#define time_after_eq(a,b) ( typecheck(unsigned long,a) &&\
typecheck(unsigned long,a) &&\
((long)(a)-(long)(b) >= 0) )
/* 當(dāng)a<=b時返回true排作,否則返回false*/
#define time_before_eq(a,b) time_after_eq(b,a)
2、時間延時
2.1短延時
- 在設(shè)備驅(qū)動程序處理硬件讀寫時亚情,往往需要延時一段短時間以使設(shè)備成功完成某些操作妄痪,因?yàn)镃PU指令執(zhí)行速度遠(yuǎn)大于硬件設(shè)備,不延時的話可能會和CPU速度匹配不上楞件。
- Linux內(nèi)核提供了2個函數(shù)來分別完成不同量級的延時(延時期間程序忙等待):
static inline void ndelay(unsigned long x);
static inline void udelay(unsigned long x);
這些函數(shù)的實(shí)現(xiàn)依賴于具體的平臺衫生,可能有的平臺硬件上根本實(shí)現(xiàn)不了納秒級的延時,此時內(nèi)核會使用一個有限循環(huán)函數(shù)來達(dá)到此目的:
static inline void ndelay(unsigned long x)
{
...
/*根據(jù)CPU頻率及x的值計算出count的值*/
while(count)
{
count--;
}
}
2.2中等延時
一般稱毫秒級的延時為中等延時土浸,內(nèi)核實(shí)現(xiàn)了3個函數(shù)(延時期間程序進(jìn)入睡眠狀態(tài)):
/* 延時msecs毫秒罪针,程序進(jìn)入睡眠,且不可被打斷 */
void msleep(unsigned int msecs);
/* 延時msecs毫秒黄伊,程序進(jìn)入睡眠泪酱,但可以被打斷 */
unsigned long msleep_interruptible(unsigned int msecs);
/* 延時msecs毫秒,程序進(jìn)入睡眠还最,且不可被打斷 */
static inline void ssleep(unsigned int secs);
2.3長延時
長延時表示驅(qū)動程序要延時相對較長的一段時間墓阀,方法主要使比較當(dāng)前jiffies值和目標(biāo)jiffies值,它是忙等待的拓轻。下例實(shí)現(xiàn)了延時10秒的目的:
unsigned long timeout = jiffies + 10*HZ斯撮;
while(time_before(jiffies, timeout));