80X86體系結構上,常用的定時器電路
實時時鐘(RTC)
RTC內核通過IRQ8上發出周期性的中斷,頻率在2-8192HZ之間,掉電後依然工作,內核通過訪問0x70和0x71 I/O端口訪問RTC。
時間戳計時器(TSC)
利用CLK輸入引線,接收外部振蕩器的時鐘信號,該計算器是利用64位的時間戳計時器寄存器來實現額,與可編程間隔定時器傳遞來的時間測量相比,更為精確。
可編程間隔定時器(PIT)
PIT的作用類似於微波爐的鬧鐘,PIT永遠以內核確定的固定頻率發出中斷,但頻率不算高。
CPU本地定時器
利用PIC或者APIC總線的時鐘計算。
高精度時間定時器(HPET)
功能比較強大,家機很少用,也不去記了。
ACPI電源管理定時器
它的時鐘信號擁有大約為3.58MHZ的固定頻率,該設備實際上是一個簡單的計數器,為了讀取計算器的值,內核需要訪問某個I/O端口,需要初始化
定時器的數據結構
利用timer_opts描述定時器
Timer_opts的數據結構
Name :標志定時器員的一個字符串
Mark_offset :記錄上一個節拍開始所經過的時間,由時鐘中斷處理程序調用
Get_offset 返回自上一個節拍開始所經過的時間
Monotonic_clock :返回自內核初始化開始所經過的納秒數
Delay:等待制定數目的“循環”
定時插補
就好像我們要為1小時35分34秒進行定時,我們不可能用秒表去統計,肯定先使用計算時的表,再用計算分的,最後才用秒表,在80x86架構的定時器也會使用各種定時器去進行定時插補,我們可以通過cur_timer指針來實現。
單處理器系統上的計時體系結構
所有與定時有關的活動都是由IRQ線0上的可編程間隔定時器的中斷觸發。
初始化階段
1. 初始化間,time_init()函數被調用來建立計時體系結構
2. 初始化xtime變量(xtime變量存放當前時間和日期,它是一個timespec類型的數據結構)
3. 初始化wall_to_monotonic變量,它跟xtime是同一類型的,但它存放將加在xtime上的描述和納秒數,這樣即使突發改變xtime也不會受到影響。
4. 看是否支持高精度計時器HPET
5. 調用select_timer()挑選系統中可利用的最好的定時資源,並讓cur_timer變量指向該定時器
6. 調用setup_irq(0,&irq0)來創建與IRQ相應的中斷門。
時鐘中斷處理程序
1. 在xtime_lock順序鎖產生一個write_seqlock()來保護與定時相關的內核變量,這樣防止中斷讓該進程被阻止。
2. 執行cur_timer定時器對象的mark_offset方法(記錄上一個節拍開始所經過的時間,由時鐘中斷處理程序調用)
3. 調用do_timer_interrupt函數,步驟為
a) 使jiffies_64值增1
b) 調用updata_times()函數來更新系統日期和時間。
c) 調用updata_process_times()函數為本地CPU執行幾個與定時相關的計數器作用。
d) 調用profile_tick()函數
e) 如果利用外部時鐘來同步系統時鐘,則每隔660秒,調用一次st_rtc_mmss()函數來調整實時時鐘。
f) 調用write_sequnlokc()釋放xtime_lock順序鎖。
4. 返回值1,報告中斷已經有效地處理了。
這個還算簡單,接下來是多處理器系統上的計時體系設計。
多處理器系統上的計時體系
初始化階段
通過calibrate_APIC_clock()計算本地APIC多久才產生一次中斷。
全局時鐘中斷處理程序
SMP版本的timer_interrupt()處理程序與UP版本的處理程序在幾個地方有差異。
Timer_interrupt()調用函數do_timer_interrupt()向I/O APIC芯片的一個端口寫入,以應答定時器的中斷要求。
Updata_process_times()函數不被調用,因為該函數執行與特定CPU相關的操作
Profile_tick()不被調用,因為該函數同樣執行與特定CPU相關的操作。
動態定時器
這部分應用很容易,但要理解動態定時器的機理,真的囧,就說說用的部分吧。
動態定時器存放在timer_list結構中
Struct time_list{
Struct list_head entry;
Spinlock_t lock;
Unsigned long magic;
Void (*function)(unsigned long);
Unsigned long data;
Tvec_base_t *base
};
Entry字段用於將軟定時器插入雙向循環鏈表隊列中,其值該鏈表根據定時器expires字段的值將他們分組放開(如果對動態定時器實現原理沒興趣的,可以無視,不需要要設置的項目)
Expries字段給出定時器到期時間,時間用拍子數表示,一般都是 unsigned long expire=timeout+jiffies
Lock自旋鎖
Function 定時產生中斷後,執行得函數
Data,可以定義一個單獨的通用函數來處理多個設備驅動程序超時的問題