《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 業(yè)界動態(tài) > linux世界里的時間

linux世界里的時間

2017-06-21
關鍵詞: Linux 計數器

      通常,,操作系統(tǒng)可以使用三種方法來表示系統(tǒng)的當前時間與日期:

 ?、僮詈唵蔚囊环N方法就是直接用一個64位的計數器來對時鐘滴答進行計數。

 ?、诘诙N方法就是用一個32位計數器來對秒進行計數,,同時還用一個32位的輔助計數器對時鐘滴答計數,,之子累積到一秒為止。因為232超過136年,,因此這種方法直至22世紀都可以讓系統(tǒng)工作得很好,。

  ③第三種方法也是按時鐘滴答進行計數,,但是是相對于系統(tǒng)啟動以來的滴答次數,,而不是相對于相對于某個確定的外部時刻;當讀外部后備時鐘(如RTC)或用戶輸入實際時間時,根據當前的滴答次數計算系統(tǒng)當前時間,。

  UNIX類操作系統(tǒng)通常都采用第三種方法來維護系統(tǒng)的時間與日期,。

  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 表示系統(tǒng)當前時間的內核數據結構

  作為一種UNIX類操作系統(tǒng),,Linux內核顯然采用本節(jié)一開始所述的第三種方法來表示系統(tǒng)的當前時間,。Linux內核在表示系統(tǒng)當前時間時用到了三個重要的數據結構:

  ①全局變量jiffies:這是一個32位的無符號整數,,用來表示自內核上一次啟動以來的時鐘滴答次數,。每發(fā)生一次時鐘滴答,內核的時鐘中斷處 理函數timer_interrupt()都要將該全局變量jiffies加1,。該變量定義在kernel/timer.c源文件中,,如下所示:

  unsigned long volatile jiffies;

  C語言限定符volatile表示jiffies是一個易該變的變量,因此編譯器將使對該變量的訪問從不通過CPU內部cache來進行,。

 ?、谌肿兞縳time:它是一個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的執(zhí)行時間帶有不確定性,因此為了記住內核上一次更新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;

 ?、廴肿兞縮ys_tz:它是一個timezone結構類型的全局變量,表示系統(tǒng)當前的時區(qū)信息,。結構類型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表示系統(tǒng)當前所處的時區(qū)信息,如下所示:

  struct timezone sys_tz;

本站內容除特別聲明的原創(chuàng)文章之外,,轉載內容只為傳遞更多信息,,并不代表本網站贊同其觀點。轉載的所有的文章,、圖片,、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創(chuàng)文章及圖片等內容無法一一聯系確認版權者,。如涉及作品內容,、版權和其它問題,請及時通過電子郵件或電話通知我們,,以便迅速采取適當措施,避免給雙方造成不必要的經濟損失,。聯系電話:010-82306118,;郵箱:[email protected]