jiffies的迴繞問題

什麼是jiffies

          在Linux內核中有一個全局變量jiffies,這個變量被定義在<linux/jiffies.h>文件中。這個全局變量是被用來記錄系統啓動以來產生的節拍的總數。在內核啓動的時候,內核將這個變量初始化爲0.此後,每次時鐘中斷時,這個值就會增加1.而每一秒內要中斷的次數是HZ。所以系統的運行時間是jiffies/HZ。

迴繞問題的產生

   在Linux系統中,對jiffies有不同的聲明。

#define __jiffy_data  __attribute__((section(".data")))
/*
 * The 64-bit value is not atomic - you MUST NOT read it
 * without sampling the sequence number in jiffies_lock.
 * get_jiffies_64() will do this for you as appropriate.
 */
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;

           對於32位機器使用的聲明是unsigned long volatile __jiffy_data jiffies,這個變量unisigned long,是一個32位的無符號數。而對於64位機器是無符號的64位無符號數。由於jiffies在使用中用的最多的是存放流失的時間,所以只關心底32位。如果要得到jiffies_64可以通過函數:

u64 get_jiffies_64(void);

           在64位機器中,jiffies只會訪問jiffies_64的低32位地址空間。

jiffies的迴繞問題

         由於jiffies變量是可能發生溢出的,對於32位無符號長整型來說它的最大值爲2^32 - 1,所以jiffies的最大值也就是4294967295.如果這個值再增加的話就會回到0然後一次增加。

    如果單純的比較大小是不準確的,如下面代碼:

unisgned long timeout = jiffies + HZ/2; /*0.5秒後超時*/
/*執行任務*/
/*查看時間是否超過*/
if (jiffies < timeout){
            /*沒有超時*/
} else {
           /*超時了*/
}

jiffies迴繞問題的解決方法

    對於jiffies的迴繞問題,Linux內核是通過4個宏定義來解決的

#define time_after(a,b)        \
    (typecheck(unsigned long, a) && \
     typecheck(unsigned long, b) && \
     ((long)((b) - (a)) < 0))
#define time_before(a,b)    time_after(b,a)

#define time_after_eq(a,b)    \
    (typecheck(unsigned long, a) && \
     typecheck(unsigned long, b) && \
     ((long)((a) - (b)) >= 0))
#define time_before_eq(a,b)    time_after_eq(b,a)


    如果現在將代碼修改成下面這樣:

unisgned long timeout = jiffies + HZ/2; /*0.5秒後超時*/
/*執行任務*/
/*查看時間是否超過*/
if (time_before(jiffies , timeout){
            /*沒有超時*/
} else {
           /*超時了*/
}

          現在就不可能再次產生迴繞了,在看上面的宏時我們會發現裏面是用的long,而不是聲明時的unsigned long。這一步就是不會產生迴繞的關鍵步驟。原因如下:

    我們都知道long是有符號的數據,它的正數範圍是[0-0x7FFFFFFF],負數是:[0x80000000-0xFFFFFFFF]之間。

(1)如果a和b都是在正數範圍,也就是0~0x7FFFFFFF之間的話,並且a > b,這時,(long)((b) - (a)) 是小於0的。

(2)如果a和b都是負數範圍,a本來是大於b,但是在負數中是a小於b,所以就出現了(long)((b) - (a))還是小於0。

(3)如果a在[0-0x7FFFFFFF],而b在[0x80000000-0xFFFFFFFF],這時(long)((b) - (a))還是小於0。

(4)如果a在[0x80000000-0xFFFFFFFF],a在[0-0x7FFFFFFF]之間。這時(long)((b) - (a))還是會小於0。

    通過上面的time_before或者是time_after都是可以繞開jiffies繞回問題的。


發佈了28 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章