linux 核心定時器及使用方法
一.度量時間差
時鐘中斷是由系統的定時硬體以週期性的時間間隔產生,這個間隔(即頻率)由核心根據hz來確定,hz是乙個與體系結構無關的常量(定義在),可配置(50-1200),在x86平台,預設值為1000.hz的含義是系統每秒鐘產生的時鐘中斷的次數.
每當時鐘中斷發生時,全域性變數jiffies(乙個32位的unsigned long 變數,定義在)就加1,因此jiffies記錄了字linux系統啟動後時鐘中斷發生的次數.驅動程式常利用jiffies來計算不同事件間的時間間隔.
核心提供了一組巨集用來比較時間量:
#include
int time_after(unsigned long a, unsigned long b);
int time_before(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
這幾個巨集可以理解為 a 巨集名 b? 1:0.
#include
struct timeval ;
void do_gettimeofday(struct timeval *tv)
二.核心定時器
核心定時器用於控制某個函式(定時器處理函式)在未來的某個特定時間執行.核心定時器註冊的處理函式只執行一次.處理過後即失效.
當核心定時器被排程執行時,幾乎可以肯定其不會在註冊這些函式的程序正在執行時.相反,它會非同步的執行.這種非同步類似於硬體中斷發生時的情景.實際上,核心定時器是被"軟體中斷"排程執行的.因此,其執行於原子上下文中.這點和tasklet很類似.處於原子上下文的程序有一些執行時的限制:
1. 不能訪問使用者空間.因為沒有程序上下文.無法與特定的程序與使用者關聯
2. 不能執行排程或休眠.
3. current指標在原子模式下無意義.
核心定時器被組織成雙向鍊錶,使用struct timer_list結構描述.
struct time_list
這3個字段表示,當jiffies等於expires時,核心會排程function函式執行.data是傳遞給function的引數的指標,如果function函式需要不止乙個引數,那麼可以將這幾個引數組成乙個結構體,並將結構體的指標賦值給data.
三.管理定時器的介面
void init_timer(struct time_list *timer);
初始化定時器佇列結構.timer_list結構在使用前必須初始化,這是要保證結構體中其他的成員能正確賦值.
void add_timer(struct time_list *timer);
啟動定時器.
int del_timer(struct time_list *timer);
在定時器超時前將定時器刪除.當定時器超時後,系統會自動將其刪除.
四.核心定時器的使用方法
初始化在使用 struct timer_list 之前,需要初始化該資料結構,確保所有的字段都被正確地設定。初始化有兩種方法。
方法一:
define_timer(timer_name, function_name, expires_value, data);
該巨集會靜態建立乙個名叫 timer_name 核心定時器,並初始化其 function, expires, name 和 base 字段。
方法二:
struct timer_list mytimer;
setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);
mytimer.expires = jiffies + 5*hz;
方法3:
struct timer_list mytimer;
init_timer(&mytimer);
mytimer ->timer.expires = jiffies + 5*hz;
mytimer ->timer.data = (unsigned long) dev;
mytimer ->timer.function = &corkscrew_timer; /* timer handler */
通過init_timer()動態地定義乙個定時器,此後,將處理函式的位址和引數繫結給乙個timer_list,
注意,無論用哪種方法初始化,其本質都只是給字段賦值,所以只要在執行 add_timer() 之前,expires, function 和 data 欄位都可以直接再修改。
關於上面這些巨集和函式的定義,參見 include/linux/timer.h。
註冊定時器要生效,還必須被連線到核心專門的鍊錶中,這可以通過 add_timer(struct timer_list *timer) 來實現。
重新註冊
要修改乙個定時器的排程時間,可以通過呼叫 mod_timer(struct timer_list *timer, unsigned long expires)。mod_timer() 會重新註冊定時器到核心,而不管定時器函式是否被執行過。
登出登出乙個定時器,可以通過 del_timer(struct timer_list *timer) 或 del_timer_sync(struct timer_list *timer)。其中 del_timer_sync 是用在 smp 系統上的(在非smp系統上,它等於del_timer),當要被登出的定時器函式正在另乙個 cpu 上執行時,del_timer_sync() 會等待其執行完,所以這個函式會休眠。另外還應避免它和被排程的函式爭用同乙個鎖。對於乙個已經被執行過且沒有重新註冊自己的定時器而言,登出函式其實也沒什麼事可做。
int timer_pending(const struct timer_list *timer)
這個函式用來判斷乙個定時器是否被新增到了核心鍊錶中以等待被排程執行。注意,當乙個定時器函式即將要被執行前,核心會把相應的定時器從核心鍊錶中刪除(相當於登出)
當刪除定時器時,必須小心乙個潛在的競爭條件。當del_timer()返回後,可以保證的只是: 定時器不會再被啟用(也就是,將來不會執行),但是在多處理機器上定時器中斷可能已經在其他處理器上執行了,所以刪除定時器時需要等待可能在其他處理器上 執行的定時器處理程式都退出,這時就要使用del_timer_sync()函式執行刪除工作:
del_timer_sync(&my_timer);
和del_timer()函式不同,del_timer_sync()函式不能在中斷上下文中使用.
特別注意:
特別要注意順序:提供兩個順序參考: 一:
struct timer_list mytimer;
init_timer(&mytimer);
mytimer.function=mytimer_function;
mytimer.expires=jiffies+hz/100
add_timer(&mytimer);
mytimer.data的值可以在第五條之前設定,也可以不設定;看自己用不用傳遞引數。 注意jiffies這個的數值是一直在變的所以第四天和第五條不要離太遠!!!!
再給乙個順序 二:
struct timer_list mytimer;
init_timer(&mytimer);
mytimer.function=mytimer_function;
add_timer(&mytimer); //沒有設定expires欄位。預設為0,立即執行mytimer_function;
。。。。。。
。。。。。。
mod_timer(&mytimer, jiffies+hz/100); //設定expires欄位。重啟定時器; 注意
jiffies這個的數值是一直在變的所以
定時器的使用方法
let date1 nsdate while true 字串類型別轉換nsstring.init format d anyobject 官方結構體都為物件 基礎型別儲存在棧空間 修改需要inout獲取位址後才可以修改 元組是物件導向的第一步,將生活邏輯中的複雜資料通過元素儲存,儲存一些複雜而且有明確...
linux 核心 核心定時器
一.時鐘中斷概念 1.時鐘中斷由系統的定時硬體以週期性的時間間隔產生,這個間隔 即頻率 由核心根據hz來確定,hz是乙個與體系結構無關的常數,可配置 50 1200 在x86平台上預設值是1000 2.每當時鐘中斷發生的時候,全域性變數jiffies unsigned long 就加1,所以jiff...
linux核心定時器
度量時間差 時鐘中斷由系統的定時硬體以週期性的時間間隔產生,這個間隔 頻率 由核心根據hz來確定,hz是乙個與體系結構無關的常數,可配置 50 1200 在x86平台,預設值為1000.每秒鐘產生1000次時鐘中斷 每當時鐘中斷發生時,全域性變數jiffies就加1,因此其記錄了自linux啟動後時...