2016年7月28日 星期四

如何撰寫Linux Kernel中的Timer機制

想要在kernel中寫Timer的機制,首先要些對一些專有名詞有一些初步的了解,分別是HZ, Tick, Jiffies.

HZ:Linux kernel 每隔固定週期會發出timer interrupt,HZ就是用來定義每一秒有幾次timer interrupts。例如:500 HZ 就是CPU每一秒會發出500個interrupt的意思。這個值是可以在Kernel的menuconfig當中來做設定.

Tick:Tick是HZ的倒數,意即timer interrupt每發生一次中斷所花的時間。如HZ為500時,tick為2毫秒 (millisecond)。

Jiffies:Jiffies為Linux核心變數(32位元變數,unsigned long),它被用來紀錄系統自開幾以來,已經過多少的tick。每發生一次timer interrupt,Jiffies變數會被加一。


接下來開始介紹Timer API的做法,我們先來看以下定義所代表的意義:

首先先宣告一個Timer的Struct:
struct timer_list timer;

這個Struct當中有幾個比較重要的值,我們要去做設定分別是:
timer.function    <===== timer 啟動後所設定的expires時間到後,會去做此參數所指定的function
timer.data             <===== timer 傳入function的參數值
timer.expires      <===== timer 延遲的時間,也就是延遲多久後去做 timer.function 所指定的函式

而下面這部分則是想要timer delay多久的寫法
Jiffies + HZ;   <=====  1秒之後 

Jiffies  + HZ/2;       <=====   半秒之後

Jiffies  + 20*HZ;     <=====  20秒之後


接下來就是實做一個Timer的Code.
/**************** Kernel_Timer *************/
struct timer_list danny_timer;

static int danny_do(void)
{
    danny_timer.expires = jiffies + HZ;
    add_timer(&danny_timer);
}

static void danny_timer_init(void)
{
    /* Timer 初始化 */
   init_timer(&danny_timer);

   /* define timer 要執行之函式 */
  danny_timer.function = danny_do;

  /* define timer 傳入函式之 Data */
  danny_timer.data = ((unsigned long) 0);

  /* define timer Delay 1秒的時間 */
  danny_timer.expires = jiffies + HZ;

  /* 啟動 Timer*/
  add_timer(&danny_timer);
}
/*********************************************/

結論:

所以當呼叫 danny_timer_init();之後,delay 1秒之後,會去做danny_do();

而danny_do()裡面也加了add_timer()的函式,所以會不斷的迴圈,每隔1秒鐘都會去做danny_do()的函式.