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);
}
發佈了15 篇原創文章 · 獲贊 5 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章