歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核定時器筆記

Linux內核定時器筆記

日期:2017/3/2 16:34:48   编辑:Linux內核

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,可以定義一個單獨的通用函數來處理多個設備驅動程序超時的問題

Copyright © Linux教程網 All Rights Reserved