核心定時器的使用
linux 核心定時器是核心用來控制在未來某個時間點(基於 jiffies )排程執行某個函式的一種機制,其實現位於和 kernel/timer.c 檔案中。
被排程的函式肯定是非同步執行的,它類似於一種「軟體中斷」,而且是處於非程序的上下文中,所以排程函式必須遵守以下規則:
1) 沒有 current 指標、不允許訪問使用者空間。因為沒有程序上下文,相關**和被中斷的程序沒有任何聯絡。
2) 不能執行休眠(或可能引起休眠的函式)和排程。
3) 任何被訪問的資料結構都應該針對併發訪問進行保護,以防止競爭條件。
核心定時器的排程函式執行過一次後就不會再被執行了(相當於自動登出),但可以通過在被排程的函式中重新排程自己來週期執行。
在 smp 系統中,排程函式總是在註冊它的同一 cpu 上執行,以盡可能獲得快取的局域性。
定時器 api
核心定時器的資料結構
struct timer_list ;
其中 expires 字段表示期望定時器執行的 jiffies 值,到達該 jiffies 值時,將呼叫 function 函式,並傳遞 data 作為引數。當乙個定時器被註冊到核心之後, entry 字段用來連線該定時器到乙個核心鍊錶中。 base 欄位是核心內部實現所用的。
需要注意的是 expires 的值是 32 位的,因為核心定時器並不適用於長的未來時間點。
初始化在使用 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)
這個函式用來判斷乙個定時器是否被新增到了核心鍊錶中以等待被排程執行。注意,當乙個定時器函式即將要被執行前,核心會把相應的定時器從核心鍊錶中刪除(相當於登出)
乙個簡單的例子
#include
#include
#include
struct timer_list mytimer;
static void myfunc(unsigned long data)
static int __init mytimer_init(void)
static void __exit mytimer_exit(void)
module_init(mytimer_init);
module_exit(mytimer_exit);
例子 2
static struct timer_list power_button_poll_timer;
static void power_button_poll(unsigned long dummy)
power_button_poll_timer.expires = jiffies + (hz / 10);
add_timer(&power_button_poll_timer);
}static void __init n2100_init_machine(void)
例子 3
裝置 open 時初始化和註冊定時器
static int corkscrew_open(struct net_device *dev)
定時器超時處理函式,對定時器的超時時間重新賦值
static void corkscrew_timer(unsigned long data)
裝置 close 時刪除定時器
static int corkscrew_close(struct net_device *dev)
例子 4
本例子用define_timer靜態建立定時器
#include
#include
#include
#include
#include
#include
static void ledtrig_ide_timerfunc(unsigned long data);
define_led_trigger(ledtrig_ide);
static define_timer(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0);
static int ide_activity;
static int ide_lastactivity;
void ledtrig_ide_activity(void)
export_symbol(ledtrig_ide_activity);
static void ledtrig_ide_timerfunc(unsigned long data)
else
}static int __init ledtrig_ide_init(void)
static void __exit ledtrig_ide_exit(void)
module_init(ledtrig_ide_init);
module_exit(ledtrig_ide_exit);
module_author("richard purdie ");
module_description("led ide disk activity trigger");
module_license("gpl");
核心 核心定時器的使用
概要 核心定時器是核心用來控制在未來某個時間點 基於jiffies 排程執行某個函式的一種機制,其實現位於 和 kernel timer.c 檔案中。被排程的函式肯定是非同步執行的,它類似於一種 軟體中斷 而且是處於非程序的上下文中,所以排程函式必須遵守以下規則 1 沒有 current 指標 不允...
核心定時器的使用
核心定時器的使用 linux 核心定時器是核心用來控制在未來某個時間點 基於 jiffies 排程執行某個函式的一種機制,其實現位於 和kernel timer.c 檔案中。被排程的函式肯定是非同步執行的,它類似於一種 軟體中斷 而且是處於非程序的上下文中,所以排程函式必須遵守以下規則 1 沒有 c...
核心定時器的使用
概要 核心定時器是核心用來控制在未來某個時間點 基於jiffies 排程執行某個函式的一種機制,其實現位於 和 kernel timer.c 檔案中。被排程的函式肯定是非同步執行的,它類似於一種 軟體中斷 而且是處於非程序的上下文中,所以排程函式必須遵守以下規則 1 沒有 current 指標 不允...