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