Linux設(shè)備驅(qū)動之定時(shí)與延時(shí)
Linux通過系統(tǒng)硬件定時(shí)器以規(guī)律的間隔(由HZ度量)產(chǎn)生定時(shí)器中斷,每次中斷使得一個內(nèi)核計(jì)數(shù)器的值jiffies累加,因此這個jiffies就記錄了系統(tǒng)啟動開始的時(shí)間流逝,然后內(nèi)核據(jù)此實(shí)現(xiàn)軟件定時(shí)器和延時(shí)。
Demo for jiffies and HZ
- #include <linux/jiffies.h>
- 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 */
內(nèi)核定時(shí)器
硬件時(shí)鐘中斷處理程序會喚起 TIMER_SOFTIRQ 軟中斷,運(yùn)行當(dāng)前處理器上到期的所有內(nèi)核定時(shí)器。
定時(shí)器定義/初始化
在Linux內(nèi)核中,timer_list結(jié)構(gòu)體的一個實(shí)例對應(yīng)一個定時(shí)器:
/* 當(dāng)expires指定的定時(shí)器到期時(shí)間期滿后,將執(zhí)行function(data) */
- /* 當(dāng)expires指定的定時(shí)器到期時(shí)間期滿后,將執(zhí)行function(data) */
- struct timer_list {
- unsigned long expires; /*定時(shí)器到期時(shí)間*/
- void (*function)(unsigned long); /* 定時(shí)器處理函數(shù) */
- unsigned long data; /* function的參數(shù) */
- ...
- };
- /* 定義 */
- struct timer_list my_timer;
- /* 初始化函數(shù) */
- void init_timer(struct timer_list * timer);
- /* 初始化宏 */
- TIMER_INITIALIZER(_function, _expires, _data)
- /* 定義并初始化宏 */
- DEFINE_TIMER(_name, _function, _expires, _data)
定時(shí)器添加/移除
- /* 注冊內(nèi)核定時(shí)器,將定時(shí)器加入到內(nèi)核動態(tài)定時(shí)器鏈表中 */
- void add_timer(struct timer_list * timer);
- /* del_timer_sync()是 del_timer()的同步版,在刪除一個定時(shí)器時(shí)需等待其被處理完,
- 因此該函數(shù)的調(diào)用不能發(fā)生在中斷上下文 */
- void del_timer(struct timer_list * timer);
- void del_timer_sync(struct timer_list * timer);
定時(shí)時(shí)間修改
- int mod_timer(struct timer_list *timer, unsigned long expires);
延時(shí)
短延時(shí)
- void ndelay(unsigned long nsecs);
- void udelay(unsigned long usecs);
- void mdelay(unsigned long msecs);
內(nèi)核在啟動時(shí),會運(yùn)行一個延遲測試程序(delay loop calibration),計(jì)算出lpj(loops per jiffy),根據(jù)lpj就實(shí)現(xiàn)了這幾個函數(shù),屬忙等待。
長延時(shí)
- 一個很直觀的方法是比較當(dāng)前的 jiffies 和目標(biāo) jiffies:
- int time_after(unsigned long a, unsigned long b); /* a after b, true */
- int time_before(unsigned long a, unsigned long b); /* a before b */
- int time_after_eq(unsigned long a, unsigned long b); /* a after or equal b */
- int time_before_eq(unsigned long a, unsigned long b);/* a before or equal b */
- 睡著延時(shí)
- void msleep(unsigned int millisecs);
- unsigned long msleep_interruptible(unsigned int millisecs);
- void ssleep(unsigned int seconds);
Tip: msleep()、 ssleep()不能被打斷。