定時器是一種軟件功能,即允許在將來的某個時刻,函數在給定的時間間隔用完時被調用。超時表示與定時器相關的時間間隔已經用完的那個時刻。
linux上考慮兩種類型的定時器,即動態定時和間隔定時器。第一種類型由內核使用,而間隔定時器由進程在用戶態創建。
動態定時器
動態定時的主要數據結構是一個叫做tvec_bases的per cpu變量,他包含NR_CPUS個元素,系統中每個CPU都有一個。每個元素是一個tvec_base_t類型的數據結構,他包含相應CPU中處理動態定時器需要的所有數據。
- struct tvec_base {
- spinlock_t lock;
- struct timer_list *running_timer;
- unsigned long timer_jiffies;
- unsigned long next_timer;
- struct tvec_root tv1;
- struct tvec tv2;
- struct tvec tv3;
- struct tvec tv4;
- struct tvec tv5;
- } ____cacheline_aligned;
字段tv1的數據解雇為tvec_root_t類型,包含一個vec數組,這個數組由256個list_head元素組成(即256個動態定時器鏈表組成)。這個結構包含了在緊接著到來的255個節拍內將要到期的所有動態定時器。
字段tv2,tv3和tv4的數據結構都是tvec_t類型,該類型有一個數組vec。這些鏈表包含在緊接著到來的2^14-1/2^20-1以及2^26-1個節拍內將要到期的所有動態定時器。
字段tv5與前面的字段幾乎相同,但唯一區別就是vec數組的最後一項是一個大expires字段值得動態定時器鏈表。tv5從不需要從其他的數組補充。
動態定時器編程
1,申請timer_list結構並對其初始化,其中必須初始化的有expires,function
- struct timer_list {
- struct list_head entry;
- unsigned long expires;
-
- void (*function)(unsigned long);
- unsigned long data;
-
- struct tvec_base *base;
- #ifdef CONFIG_TIMER_STATS
- void *start_site;
- char start_comm[16];
- int start_pid;
- #endif
- #ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
- #endif
- };
2,調用init_timer函數初始化
該函數最終調用下面函數
- static void __init_timer(struct timer_list *timer,
- const char *name,
- struct lock_class_key *key)
- {
- timer->entry.next = NULL;
- timer->base = __raw_get_cpu_var(tvec_bases);
- #ifdef CONFIG_TIMER_STATS
- timer->start_site = NULL;
- timer->start_pid = -1;
- memset(timer->start_comm, 0, TASK_COMM_LEN);
- #endif
- lockdep_init_map(&timer->lockdep_map, name, key, 0);
- }
可看到初始化的幾個相關變量。