Linux裝置驅動 核心定時器

2021-10-18 16:28:54 字數 3339 閱讀 2360

核心定時器使用

核心定時器是核心用來控制在未來某個時間點(基於jiffies)排程執行某個函式的一種機制,其實現位於  和 kernel/timer.c 檔案中。

被排程的函式肯定是非同步執行的,它類似於一種「軟體中斷」,而且是處於非程序的上下文中,所以排程函式必須遵守以下規則:

1) 沒有 current 指標、不允許訪問使用者空間。因為沒有程序上下文,相關**和被中斷的程序沒有任何聯絡。

2) 不能執行休眠(或可能引起休眠的函式)和排程。

3) 任何被訪問的資料結構都應該針對併發訪問進行保護,以防止競爭條件。 

核心定時器的排程函式執行過一次後就不會再被執行了(相當於自動登出),但可以通過在被排程的函式中重新排程自己來週期執行。

在smp系統中,排程函式總是在註冊它的同一cpu上執行,以盡可能獲得快取的局域性。

核心定時器的資料結構

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;

void init_timer(struct timer_list *timer);

上述init_timer函式將初始化struct timer_list的 entry的next 為 null ,並未base指標賦值 

tm->expires = ;

tm->function = ;

tm->data = ; 

setup_timer(&mytimer, (*function)(unsigned long), unsigned long data);
方法也可以用於初始化定時器並賦值其成員,源**為:

static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data)

注意,無論用哪種方法初始化,其本質都只是給字段賦值,所以只要在執行 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);
這個函式用來判斷乙個定時器是否被新增到了核心鍊錶中以等待被排程執行。注意,當乙個定時器函式即將要被執行前,核心會把相應的定時器從核心鍊錶中刪除(相當於登出)。

使用範例

/* 實現每隔一秒向核心log中列印一條資訊 */

#include #include #include #include #include static struct timer_list tm;

struct timeval oldtv;

void callback(unsigned long arg)

static int __init demo_init(void)

static void __exit demo_exit(void)

module_init(demo_init);

module_exit(demo_exit);

module_license("gpl");

module_author("farsight");

module_description("demo for kernel module");

一些和時間相關的內容

linux/jiffies.h

計數值:

jiffies

u64 get_jiffies_64(void)

asm/param.h

每秒觸發中斷的次數

hz時間值

秒數=(jiffies(new) - jiffies(old))/hz

jiffies(new) = jiffies(old) + 秒*hz

---------------------------------------------

linux/delay.h

延時函式

void ssleep(unsigned int seconds);

void msleep(unsigned int msecs);

---------------------------------------------

時間函式

linux/time.h

void do_gettimeofday(struct timeval *tv)

Linux裝置驅動開發 核心定時器

1.linux核心定時器是核心用來控制在未來某個時間點 基於jiffies 排程執行某個函式的一種機制,其實現位於 和 kernel timer.c 檔案中。2.被排程的函式是非同步執行的,它類似於一種 軟體中斷 而且是處於非程序的上下文中,所以排程函式必須遵守以下規則 1 沒有 current 指...

《Linux裝置驅動開發詳解》 核心定時器

10.5.1 核心定時器程式設計 軟體意義上的定時器最終依賴硬體定時器來實現,核心在時鐘中斷發生後檢測各定時器是否到期,到期後的定時器處理函式將作為軟中斷在底半部執行。實質上,時鐘中斷處理程式執行 update process timers 函式,該函式呼叫run local timers 函式,這...

linux核心驅動之定時器

運用場景 1.初始化乙個驅動,經過一定的時間再執行乙個特殊動作 2.初始化乙個驅動,之後每隔一定的時間執行乙個特殊動作 定時器工作流程 a.建立timer,編寫定時器處理函式 b.為timer的expires data function賦值 c.呼叫add timer將timer加入列表 d.定時器...