定時器和時間管理
系統定時器是一種可程式化硬體晶片,它能以固定頻率產生中斷。該中斷就是所謂的定時器中斷,它所對應的中斷處理常式負責更新系統時間,還負責執行需要周期性啟動並執行任務。系統定時器和時鐘中斷處理常式是Linux系統核心管理機制中的中樞。
另外一個關注的焦點是動態定時器——一種用來延遲執行程式的工具。比如說,如果軟碟機馬達在一定時間內都未活動,那麼磁碟片驅動程式會使用動態定時器關閉軟碟機馬達。核心可以動態建立或銷毀動態定時器。
1.核心中的時間概念
系統定時器以某種頻率自行觸發時鐘中斷,該頻率可以通過編程預定,稱為節拍率(tick rate)。連續兩次時鐘中斷的間隔時間稱為節拍(tick),它等於節拍率分之一秒。
2.節拍率HZ
系統定時器頻率(節拍率)是通過靜態預先處理定義的,也就是HZ,在系統啟動時按照HZ值對硬體進行設定。體繫結構不同,HZ的值也不同,其中 arm 是 100HZ,i386 是 1000HZ。
提高節拍率意味著時鐘中斷產生得更加頻繁,所以中斷處理常式也會更頻繁地執行,如此一來會給整個系統帶來如下好處:
1)核心定時器能夠以更高的頻度和更高的準確度運行。
2)依賴定時值執行的系統調用,比如 poll 和 select,能夠以更高的精度運行。
3)對諸如資源消耗和系統已耗用時間等的測量會有更精細的解析度。
4)提高進程搶佔的準確度。
提高節拍率也會產生負作用:節拍率越高,意味著時鐘中斷頻率越高,也就意味著系統負擔越重。
3.jiffies
全域變數 jiffies 用來記錄自系統啟動以來產生的節拍的總數。啟動時,核心將該變數初始化為0,此後,每次時鐘中斷處理常式都會增加該變數的值。因為一秒內時鐘中斷的次數等於HZ,系統已耗用時間以秒為單位就等於 jiffies/HZ。
jiffies 變數總是無符號長整數(unsigned long),因此,在32位體繫結構上是32位,在64位體繫結構是64位,當 jiffies 的值超過它的最大存放範圍後就會發生溢出,它的值會迴繞到0。
核心提供了四個宏來協助比較節拍計數,它們能正確地處理節拍計數迴繞情況。這些宏定義在檔案<linux/jiffies.h>中:
#define time_after( unknown, known ) ((long)(known) - (long)(unknown) < 0)#define time_before( unknown, known ) ((long)(unknown) - (long)(known) < 0)#define time_after_eq( unknown, known ) ((long)(unknown) - (long)(known) >= 0)#define time_before_eq( unknown, known ) ((long)(known) - (long)(unknown) >= 0)
其中 unknown 參數通常是 jiffies,known 參數是需要對比的值。
4.硬時鐘和定時器
系統時鐘(RTC)是用來持久存放系統時間的裝置,即使系統關閉後,也可以依靠主板上的微型電池提供的電力保持系統的計時。當系統啟動時,核心通過讀取RTC來初始化牆上時間,該時間存放在 xtime 變數中。
系統定時器是核心定時機制中最為重要的角色,它提供一種周期性觸發中斷機制。
5.時鐘中斷處理常式
時鐘中斷處理常式可以劃分為兩個部分:體繫結構相關部分和體繫結構無關部分。與體繫結構相關的常式作為系統定時器的中斷處理常式而註冊到核心中,以便在產生時鐘中斷時,它能夠相應地運行。雖然處理常式的具體工作依賴於特定的體繫結構,但是絕大多數處理常式最低限度都要執行如下工作:
1)獲得 xtime_lock 鎖,以便對訪問 jiffies_64 和牆上時間 xtime 進行保護。
2)需要時應答或重新設定系統時鐘。
3)周期性地使用牆上時間更新系統時鐘。
4)調用體繫結構無關的時鐘常式:do_timer()。
中斷服務程式主要通過調用與體繫結構無關的常式 do_timer 執行下面的工作:
1)給 jiffies_64 變數增加 1 (這個操作即使是在 32 位體繫結構上也是安全的,因為前面已經獲得了 xtime_lock 鎖)。
2)更新資源消耗的統計值,比如當前進程所消耗的系統時間和使用者時間。
3)執行已經到期的動態定時器。
4)執行 scheduler_tick 函數。
5)更新牆上時間,該時間存放在 xtime 變數中。
6)計算平均負載值。