linux世界裡的時間

來源:互聯網
上載者:User
 

通常,作業系統可以使用三種方法來表示系統的目前時間與日期:①最簡單的一種方法就是直接用一個64位的計數器來對時鐘滴答進行計數。②第二種方法就是用一個32位計數器來對秒進行計數,同時還用一個32位的輔助計數器對時鐘滴答計數,之子累積到一秒為止。因為232超過136年,因此這種方法直至22世紀都可以讓系統工作得很好。③第三種方法也是按時鐘滴答進行計數,但是是相對於系統啟動以來的滴答次數,而不是相對於相對於某個確定的外部時刻;當讀外部後備時鐘(如RTC)或使用者輸入實際時間時,根據當前的滴答次數計算系統目前時間。 UNIX類作業系統通常都採用第三種方法來維護系統的時間與日期。  1 基本概念 首先,有必要明確一些Linux核心時鐘驅動中的基本概念。 (1)刻度(clock cycle)的頻率:8253/8254 PIT的本質就是對由晶體振蕩器產生的刻度進行計數,晶體振蕩器在1秒時間內產生的時鐘脈衝個數就是刻度的頻率。Linux用宏CLOCK_TICK_RATE來表示8254 PIT的輸入時鐘脈衝的頻率(在PC機中這個值通常是1193180HZ),該宏定義在include/asm-i386/timex.h標頭檔中: #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ (2)時鐘滴答(clock tick):我們知道,當PIT通道0的計數器減到0值時,它就在IRQ0上產生一次時鐘中斷,也即一次時鐘滴答。PIT通道0的計數器的初始值決定了要過多少刻度才產生一次時鐘中斷,因此也就決定了一次時鐘滴答的時間間隔長度。 (3)時鐘滴答的頻率(HZ):也即1秒時間內PIT所產生的時鐘滴答次數。類似地,這個值也是由PIT通道0的計數器初值決定的(反過來說,確定了時鐘滴答的頻率值後也就可以確定8254 PIT通道0的計數器初值)。Linux核心用宏HZ來表示時鐘滴答的頻率,而且在不同的平台上HZ有不同的定義值。對於ALPHA和IA62平台HZ的值是1024,對於SPARC、MIPS、ARM和i386等平台HZ的值都是100。該宏在i386平台上的定義如下(include/asm-i386/param.h): #ifndef HZ #define HZ 100 #endif 根據HZ的值,我們也可以知道一次時鐘滴答的具體時間間隔應該是(1000ms/HZ)=10ms。 (4)時鐘滴答的時間間隔:Linux用全域變數tick來表示時鐘滴答的時間間隔長度,該變數定義在kernel/timer.c檔案中,如下: long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ tick變數的單位是微妙(μs),由於在不同平台上宏HZ的值會有所不同,因此方程式tick=1000000÷HZ的結果可能會是個小數,因此將其進行四捨五入成一個整數,所以Linux將tick定義成(1000000+HZ/2)/HZ,其中被除數運算式中的HZ/2的作用就是用來將tick值向上圓整成一個整型數。 另外,Linux還用宏TICK_SIZE來作為tick變數的引用別名(alias),其定義如下(arch/i386/kernel/time.c): #define TICK_SIZE tick (5)宏LATCH:Linux用宏LATCH來定義要寫到PIT通道0的計數器中的值,它表示PIT將沒隔多少個刻度產生一次時鐘中斷。顯然LATCH應該由下列公式計算: LATCH=(1秒之內的刻度個數)÷(1秒之內的時鐘中斷次數)=(CLOCK_TICK_RATE)÷(HZ) 類似地,上述公式的結果可能會是個小數,應該對其進行四捨五入。所以,Linux將LATCH定義為(include/linux/timex.h): /* LATCH is used in the interval timer and ftape setup. */ #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ 類似地,被除數運算式中的HZ/2也是用來將LATCH向上圓整成一個整數。  2 表示系統目前時間的核心資料結構 作為一種UNIX類作業系統,Linux核心顯然採用本節一開始所述的第三種方法來表示系統的目前時間。Linux核心在表示系統目前時間時用到了三個重要的資料結構: ①全域變數jiffies:這是一個32位的不帶正負號的整數,用來表示自核心上一次啟動以來的時鐘滴答次數。每發生一次時鐘滴答,核心的時鐘中斷處理函數timer_interrupt()都要將該全域變數jiffies加1。該變數定義在kernel/timer.c源檔案中,如下所示: unsigned long volatile jiffies; C語言限定符volatile表示jiffies是一個易該變的變數,因此編譯器將使對該變數的訪問從不通過CPU內部cache來進行。 ②全域變數xtime:它是一個timeval結構類型的變數,用來表示目前時間距UNIX時間基準1970-01-01 00:00:00的相對秒數值。結構timeval是Linux核心表示時間的一種格式(Linux核心對時間的表示有多種格式,每種格式都有不同的時間精度),其時間精度是微秒。該結構是核心表示時間時最常用的一種格式,它定義在標頭檔include/linux/time.h中,如下所示: struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ }; 其中,成員tv_sec表示目前時間距UNIX時間基準的秒數值,而成員tv_usec則表示一秒之內的微秒值,且1000000>tv_usec>=0。 Linux核心通過timeval結構類型的全域變數xtime來維持目前時間,該變數定義在kernel/timer.c檔案中,如下所示: /* The current time */ volatile struct timeval xtime __attribute__ ((aligned (16))); 但是,全域變數xtime所維持的目前時間通常是供使用者來檢索和設定的,而其他核心模組通常很少使用它(其他核心模組用得最多的是jiffies),因此對xtime的更新並不是一項緊迫的任務,所以這一工作通常被延遲到時鐘中斷的底半部分(bottom half)中來進行。由於bottom half的執行時間帶有不確定性,因此為了記住核心上一次更新xtime是什麼時候,Linux核心定義了一個類似於jiffies的全域變數wall_jiffies,來儲存核心上一次更新xtime時的jiffies值。時鐘中斷的底半部分每一次更新xtime的時侯都會將wall_jiffies更新為當時的jiffies值。全域變數wall_jiffies定義在kernel/timer.c檔案中: /* jiffies at the most recent update of wall time */ unsigned long wall_jiffies; ③全域變數sys_tz:它是一個timezone結構類型的全域變數,表示系統當前的時區資訊。結構類型timezone定義在include/linux/time.h標頭檔中,如下所示: struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of dst correction */ }; 基於上述結構,Linux在kernel/time.c檔案中定義了全域變數sys_tz表示系統當前所處的時區資訊,如下所示: struct timezone sys_tz;

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.