linux時鐘RTC,TSC,PIT,jiffies

1 基本概念

定時機制連同一些更可見的內核活動(如檢查超時)來驅使進程切換。

兩種主要的定時測量:

  • 保存當前的時間和日期,以便能通過time(), ftime()和gettimeofday()系統調用把它們返回給用戶程序。
  • 維持定時器,這種機制能夠告訴內核或用戶程序某一時間間隔已經過去了。

定時測量是由基於固定頻率振盪器和計數器的幾個硬件電路完成的。


2 時鐘和定時器電路

時鐘電路用於跟蹤當前時間和產生精確的時間度量。

定時器電路由內核編程,所以它們以udingde,預先定義的頻率發出中斷。

時鐘電路的分類

  • 用於跟蹤當前時間
    • 實時時鐘RTC
    • 時間戳計數器TSC
  • 產生週期性的時鐘中斷,用於計時
    • 可編程間隔定時器PIT


2.1 實時時鐘RTC——IRQ8上產生中斷

當PC被切斷電源,RTC還繼續工作。

內核通過0x70和0x71I/O端口訪問RTC。

能在IRQ8上發出週期性的中斷,頻率在2HZ~8192HZ之間,可編程


2.2 時間戳計數器TSC

在80x86微處理器中,有一個CLK輸入引線接收外部振盪器的時鐘信號。TSC在每個時鐘信號到來時加1.

TSC是一個64位的時間戳計數器寄存器,彙編指令rdtsc讀這個寄存器。Linux在初始化時系統時必須確定時鐘信號的頻率。


獲得tsc的時鐘頻率:calibrate_tsc()函數通過計算一個大約在5ms的時間間隔內所產生的時鐘信號的個數來算出CPU實際頻率。

Linux通過rdtscll()或rdtscl()用來讀取TSC的事。

與可編程間隔定時器相比,TSC可以獲得更精確的時鐘。


2.3 可編程間隔定時器PIT

使用I/O端口0x40~0x43

LInux給PC的第一個PIT進行編程,使它以大於1000Hz的頻率向IRQ0發出時鐘中斷,即每1ms產生一次時鐘中斷,這個時間間隔叫做一個節拍(tick),它的長度以納秒爲單位存放在tick_nsec變量中。


由setup_pit_timer()進行初始化。在init_pit_timer()中初始化時鐘中斷頻率。

與系統時鐘信號有關的宏定義:

(1)宏定義Hz

在不同的體系機構下,系統時鐘所要求的可編程定時器中斷的頻率,即每秒tick的個數

(2)宏定義CLOCK_TICK_RATE

記錄了不同體系結構下,驅動可編程定時器工作的輸入時鐘頻率

(3)宏定義LATCH

記錄了上述兩個宏定義的比值,用於在內核初始化過程中設置可編程定時器中計數器寄存器counter的初始值。


3 Linux計時體系結構

LInux的計時體系結構是一組與時間流相關的內核數據結構和函數。

功能:

  • 更新自系統啓動以來所經過的時間
  • 更新時間和日期
  • 確定當前進程的執行時間,考慮是否要搶佔
  • 更新資源使用統計計數
  • 檢查到期的軟定時器

內核有兩個基本的計時函數:

  • 保持當前最新的時間
  • 計算在當前秒內走過的納秒數

在單處理器系統中,所有定時活動都由IRQ0上的時鐘中斷觸發,包括:

  • 在中斷中立即執行的部分
  • 作爲下半部分延遲執行的部分

3.1 計時體系結構的數據結構

3.1.1定時器對象(時鐘源)

爲了使用一種統一的方法來處理可能存在的定時器資源,內核使用能夠了“定時器對象”,它是timer_opts類型的一個描述符。其中最重要的兩個方法:

mark_offset:由時鐘中斷處理程序調用,並以適當的數據結構記錄每個節拍到來時的準確時間。

get_offset:使用已記錄的值來計算上一次時鐘中斷(節拍)以來經過的時間。

這兩種方法,使得Linuxd計時體系結構能夠打到子節拍的分辨率,也就是說,內核能夠以比節拍週期更高的精度來測定當前的時間,這種操作被稱爲“定時插補”。


在內核初始化期間,select_timer()函數設置cur_timer指向適當定時器對象(時鐘源)的地址。變量timer_cur存放了某個定時器對應的那個的地址,該定時器是系統可利用的定時器資源中最好的。





3.1.2jiffies變量

一個計數器,用來記錄自系統啓動以來產生的節拍總數。

因爲一秒鐘內產生系統時鐘中斷次數等於宏定義HZ的值,所以變量jiffies的值在一秒內增加HZ。


3.1.3xtime變量

xtime變量存放當前時間和日期,它是一個timespec類型的數據結構。以便內核對某些對象和事件作時間標記,如記錄文件的創建時間、修改時間、上次訪問時間,或者供用戶進程通過系統調用來使用。

基本每個tick更新一次。


3.2 單處理器系統上的計時體系結構

考點:tick_handle_periodic函數的功能(Linux的計時體系結構的功能)


tick_init調用clockevents_tegister_notifier註冊tick_notifier到clockevents_chain上。

Update_wall_time()完成變量xtime的更新。

time_init_hook()來設置系統時鐘中斷處理程序。


在時鐘中斷處理函數中:

會調用tick_init函數,書上很多流程中的函數最終都是被這個函數所調用,流程如下:



4 軟定時器和延遲函數

軟定時器:

  • 動態定時器(內核)
  • 間隔定時器(可以用戶)

動態定時器:被動態的創建和撤銷,當前活動的動態定時器個數沒有限制

定時器是一種軟件功能,即允許在將來的某個時刻,函數在給定的時間間隔用完時被調用。每個定時器都包含一個字段,表示定時器將需要多長時間纔到期。這個字段的初值就是jiffies的當前值加上合適的節拍數。

注意,對於必須嚴格遵守定時時間的那些實時應用而言,定時器並不適合,因爲定時器的檢查總是由可延遲函數進行。



4.1創建並激活一個動態定時器——init_timer初始化一個time_list對象

  • 創建一個新的timer_list對象
  • 調用init_timer初始化,並設置定時器要處理的函數和參數
  • 設置定時時間
  • 使用add_timer加入到合適的鏈表中
具體的步驟:

4.2動態定時器的數據結構

用於和系統核心變量jiffies進行比較。
  • 成員變量function:該函數指針變量保存了內核定時器超時後要執行的函數,即定時器超時處理函數。
  • 成員變量data:該無符號長整型變量用作定時器超時處理函數的參數。
  • 成員變量base:該指針變量表明瞭該內核定時器節點歸屬於系統中哪一個處理器,在使用函數init_timer()初始化內核定時器節點的過程中,將該指針指向了一個每處理器變量tvec_bases的成員變量t_base。

4.3動態定時器的維護


run_timer的主要功能

  • 定時器時間表示參數加一
  • 處理的定時器去除
  • 依次處理到期定時器

動態定時器應用之delayed work

動態定時器應用之schedule_timeout:  setup_time_on_stack(&timer, process_timeout, (unsigned long)current);  timer時間到了之後,process_timeout函數將當前進程變爲等待態。

  

4.4延遲函數:

當內核需要等待一個較短的時間間隔,如幾毫秒,通常設備驅動器會等待預先定義的整個微秒直到硬件完成某些操作。這些情況下,內核使用udelay()和ndelay()函數:前者接收一個微秒級的時間間隔作爲它的參數,並在指定的延遲結束後返回,後者與前者類似,但是指定延遲的參數是納秒級的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章