5-3 Linux內核計時、延時函數與內核定時器【轉】


轉自:http://www.xuebuyuan.com/510594.html

5-3 Linux內核計時、延時函數與內核定時器 

計時

1、 
內核時鍾

1.1   
內核通過定時器(timer)中斷來跟蹤時間流

1.2   
硬件定時器以周期性的間隔產生時間中斷,這個間隔(即頻率)由內核根據HZ來確定,HZ是一個與體系結構無關的常數。

1.3   
這個時間間隔通常取1ms到10ms.

2、 
jiffies計算器

2.1每次當定時器中斷發生時,內核內部通過一個64位的變量jiffies_64做加一計數。

2.2驅動程序開發者通常訪問的是jiffies變量,它是jiffes_64的低32位。

2.3jiffies是unsigned
long型的變量,該變量被聲明為volatile,這樣可避免編譯器對訪問該變量的語句的優化。

2.4jiffies記錄了自最近一次Linux啟動后到當前的時間間隔(即時鍾中斷發生的次數)。驅動程序常利用jiffies來計算不同事件間的時間間隔。

3、HZ

3.1 HZ表每秒中產生的定時中斷次數

3.2 HZ就代表1秒,HZ/2就代表0.5秒

4、使用jiffies計數器

  
#include<linux/jiffies.h>

  
Unsigned long  current_i,  stamp_1, 
stamp_half,  stamp_n;

  
Current_i = jiffies;  //讀取當前的值

  
Stamp_1 = current_i+HZ;  //未來的一秒

  
Stamp_half = current_i +HZ/2 ; //未來的半秒

  
Stamp_n = current_i + n*HZ/1000; //未來的n毫秒

5、為了防止jiffies溢出導致問題,最好使用宏比較

  
#include<linux/jiffies.h>

  
Int time_after(unsigned long a, unsigned long b);//判斷a代表的時間是否在b之后。

  
Int time_before(unsigned long a,unsigned long b);

  
Int time_after_eq(unsigned long a ,unsigned long b);

  
Int time_before_eq(unsigned long a,unsigned long b);

6、

(1)用戶空間的timeval

struct timeval{

 
time_t tv_sev;//秒、

 
suseconds_t tv_usec;//毫秒

}

(2)用戶空間的timespec

 
struct timespec{

    
time_t tv_sec;//秒

    
long  tv_nsec;//納秒

  
}

7、內核空間jiffies和用戶空間的timeval、timevspec的轉換。

 
#include<linux/time.h>

  
unsigned long timespec_to_jiffies(struct timespec* value);

void jiffies_to_timespec(unsigned long jiffie,struct timespec* value);

unsigned long timeval_to_jiffies(struct timeval* value);

void jiffies_to_timeval(unsigned long jiffies, struct 
timeval* value);

8、獲取當前時間

  
#include<linux/time.h>
   void do_gettimeofday(struct timeval*  
tv);

  
struct timespec current_kernel_time(void);

9、使用jiffies延時(如果對延時的精度要求不是很高時,用忙等待)

  
unsigned long j = jiffies + delay*HZ

  
while(jiffies<j){  //jiffies表當前的滴答值,是不停地走的。
  
/*do nothing*/

  
}

10、長延遲。

while(time_before(jiffies,end_time)){

  
Schedule();//在end_time之前,則調度

}

 

#include<linux/sched.h>
    signed long schedule_timeout(signed long timeout);//使用jiffies表示的延遲。先做超時,

典型應用:

 set_current_state(TASK_INTERRUPTIBLE);//設置狀態值,設置為可中斷的睡眠

 schedule_timeout(delay);//延時

11、短延時(忙等待延時,不發生休眠)

#include<linux/delay> 

//以下三個延時函數均是忙等待函數,因而在延遲過程中午飯運行其他任務。不發生休眠的。

void ndelay(unsigned long nsecs); //延時納秒

void udelay(unsigned long usecs);//延時微秒

void mdelay(unsigned long msecs);//延時毫秒

12、不用忙等待的延時方式(將調用進程休眠給定時間)

#include<linux/delay.h>

void msleep(unsigened int millisecs);//休眠millisecs毫秒
不可中斷的休眠millisecs毫秒

unsigned long msleep_interruptible(unsigned int millisecs);//可中斷的休眠

void ssleep(unsigned int seconds);//休眠seconds秒。

 

內核定時器:

13、定時器用於控制某個函數(定時器處理函數)在未來的某個特定時間執行。內核定時器注冊的處理函數只執行一次—不是循環執行的。

14、內核定時器被組織成雙向鏈表,並使用struct
time_list 結構描述。

#include<linux/timer.h>

struct timer_list{

 
unsigned long expires;  //超時的jiffies

 
void (*function)(unsigned long);//超時處理函數

  
unsigned long data; //超時處理函數參數。

};

15、內核定時器操作函數

15.1初始化(初始化定時器隊列結構)

   
void init_timer(struct timer_list * timer);

   
struct timer_list TIMER_INITIALIZER(_function,_expires,_data);

15.2添加定時器(啟動定時器,開始倒計時)

   
void add_timer(struct time_list *tiemer0:

15.3刪除定時器(在定時器超時前將它刪除。定時器超時后,系統會自動地將它刪除)

15.4內核定時器使用模板

   
static struct timer_list  key_timer;//定義內核定時器對象

   
static void key_timer_handle(unsigned ong data)//定時器處理函數

   
{

     
……

     
//定時器處理函數具體執行代碼

     
……

     
// 定時器參數的更新,重啟定時器

     
key_timer.expires = jiffies+ KEY_TIMER_DELAY;

   
  add_time(&key_time); 
 //賦新值,可以實現
循環

     
……

}

 

//設備驅動模塊加載函數

static int__ init xxx_init(void)

{

 
……

 
//初始化內核定時器

  init_time(&key_timer);

 
key_timer.function=&key_timer_handle;

 
key_timer.data = (unsigned long)key_desc;

 
key_timer.expires = jiffies+KEY_TIMER_DELAY;

 

 
//添加內核定時器(這是第一次啟動)

 
add_time(&key_time);  

……

}

 

Static void__exit xxx_exit(void)

{
              ……

  
//刪除定時器

  
del_timer(&key_timer);

  
……

}

16、內核定時器與tasklet比較

16.1相同點:
在中斷期間運行,時鍾會在調度他們的同一個cpu上運行,軟件中斷的上下文,原子模式運行。(軟件中斷時打開硬件中斷的同時執行某些異步任務的一種內核機制) 

 16.2不同的:不能要求TASKLECT在給定的時間執行。

 

聲明:本文非原創,整理自申嵌 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM