(筆記)Linux內核學習(八)之定時器和時間管理
一 內核中的時間觀念
內核在硬件的幫助下計算和管理時間。硬件為內核提供一個系統定時器用以計算流逝的時間。系
統定時器以某種頻率自行觸發,產生時鐘中斷,進入內核時鐘中斷處理程序中進行處理。
墻上時間和系統運行時間根據時鐘間隔來計算。
利用時間中斷周期執行的工作:
更新系統運行時間;
更新實際時間;
在smp系統上,均衡調度程序中各處理器上運行隊列;
檢查當前進程是否用盡了時間片,重新進行調度;
運行超時的動態定時器;
更新資源消耗和處理器時間的統計值;
二 節拍率
系統定時器的頻率;通過靜態預處理定義的——HZ;系統啟動按照HZ值對硬件進行設置。體系結構不同,HZ值也不同;HZ可變的。
//內核時間頻率
#define HZ 1000
提高節拍率中斷產生更加頻繁帶來的好處:
提高時間驅動事件的解析度;
提高時間驅動事件的準確度;
內核定時器以更高的頻度和準確度;
依賴頂上執行的系統調用poll()和select()能更高的精度運行;
系統時間測量更精細;
提高進程搶占的準確度;
提高節拍率帶來的副作用:
中斷頻率增高系統負擔增加;
中斷處理程序占用處理器時間增多;
頻繁打斷處理器高速緩存;
節拍率HZ值需要在其中進行平衡。
三 jiffies
jiffies:全局變量,用來記錄自系統啟動以來產生的節拍總數。啟動時內核將該變量初始化為0;
此後每次時鐘中斷處理程序增加該變量的值。每一秒鐘中斷次數HZ,jiffies一秒內增加HZ。系統運行時間 = jiffie/HZ.
jiffies用途:計算流逝時間和時間管理
jiffies內部表示:
extern u64 jiffies_64;
extern unsigned long volatile jiffies; //位長更系統有關32/64
32位:497天後溢出
64位:……
//0.5秒後超時 unsigned long timeout = jiffies + HZ/2; …… //註意jiffies值溢出回繞用宏time_before 而非 直timeout > jiffies if(time_before(jiffies,timeout)){ //沒有超時 }else{ //超時 }
四 硬時鐘和定時器
兩種設備進行計時:系統定時器和實時時鐘。
實時時鐘(RTC):用來持久存放系統時間的設備,即便系統關閉後,靠主板上的微型電池提供電力保持系統的計時。
系統啟動內核通過讀取RTC來初始化墻上時間,改時間存放在xtime變量中。
系統定時器:內核定時機制,註冊中斷處理程序,周期性觸發中斷,響應中斷處理程序,進行處理執行以下工作:
l 獲得xtime_lock鎖,訪問jiffies和更新墻上時間xtime;
l 更新實時時鐘;
l 更新資源統計值:當前進程耗時,系統時間等;
l 執行已到期的動態定時器;
l 執行scheduler_tick()
//中斷處理程序 irqreturn_t timer_interrupt(int irq, void *dev) { //ticks have passed long nticks; xtime_update(nticks); while (nticks--) update_process_times(user_mode(get_irq_regs())); return IRQ_HANDLED; } void xtime_update(unsigned long ticks) { //seq鎖 write_seqlock(&xtime_lock); do_timer(ticks); write_sequnlock(&xtime_lock); } void do_timer(unsigned long ticks) { jiffies_64 += ticks; //更新墻上時間 ——實際時間 update_wall_time(); calc_global_load(ticks); } void update_process_times(int user_tick) { struct task_struct *p = current; //計算當前進程執行時間 account_process_tick(p, user_tick); //觸發軟中斷TIMER_SOFTIRQ 超時的timer run_local_timers(); //計算進程時間片 scheduler_tick(); }
五 定時器
定時器:管理內核時間的基礎,推後或執行時間執行某些代碼。
定時器數據結構:
struct timer_list { struct list_head entry; //定時值基於jiffies unsigned long expires; //定時器內部值 struct tvec_base *base; //定時器處理函數 void (*function)(unsigned long); //定時器處理函數參數 unsigned long data; …… };
定時器使用:
struct timer_list my_timer; //初始化定時器 init_timer(&my_timer); …… //激活定時器 add_timer(&my_timer); //刪除定時器 del_timer(my_timer); ……
六 延遲執行
使用定時器和下半部機制推遲執行任務。還有其他延遲執行的機制:
忙等待:
利用節拍,精確率不高
unsigned long delay = jiffies + 2*HZ ; //2秒 節拍整數倍才行;
while(time_before(jiffies,delay))
;
短延遲:延遲時間精確到毫秒,微妙;短暫等待某個動作完成時,比時鐘節拍更短;依靠數次循環達到延遲效果。
void udelay(unsigned long usecs)
void mdelay(unsigned long msecs)
schedule_timeout()延遲:使執行的任務睡眠指定時間,達到延遲
signed long __sched schedule_timeout(signed long timeout) { struct timer_list timer; unsigned long expire; switch (timeout) { case MAX_SCHEDULE_TIMEOUT: //無限期睡眠 schedule(); goto out; default: if (timeout < 0) { current->state = TASK_RUNNING; goto out; } } //超時時間 expire = timeout + jiffies; //初始化一個timer定時器 參數current task setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); /* Remove the timer from the object tracker */ destroy_timer_on_stack(&timer); timeout = expire - jiffies; out: return timeout < 0 ? 0 : timeout; } static void process_timeout(unsigned long __data) { //喚醒被睡眠的任務 wake_up_process((struct task_struct *)__data); }
(筆記)Linux內核學習(八)之定時器和時間管理