歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux的動態定時器--時間輪

Linux的動態定時器--時間輪

日期:2017/3/1 10:20:18   编辑:Linux編程

Linux的定時器—有時也稱為動態定時器或內核定時器—是管理內核時間的基礎。定時器是一種軟件功能,即允許在將來的某個時刻,函數在給定的時間間隔用完時被調用。注意的是定時器並不會周期運行,它在超時後就自行銷毀,這也是定時器被稱為動態定時器的一個原因。動態定時器不斷地創建和銷毀,而且它的運行次數也不受限制。

定時器在內核代碼中屬於一個基礎組件。要想完全弄清楚linux2.6中內核定時器的實現,得先從初始化開始。

在start_kernel(void)-->init_timers(void)

  1. void __init init_timers(void)
  2. {
  3. int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
  4. (void *)(long)smp_processor_id());
  5. init_timer_stats();
  6. BUG_ON(err == NOTIFY_BAD);
  7. register_cpu_notifier(&timers_nb);
  8. open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
  9. }

在timer_cpu_notify(&timers_nb,(unsigned long)CPU_UP_PREPARE,

(void*)(long)smp_processor_id());

中執行

init_timers_cpu(cpu) //初始化本cpu中的timers

初始化的主要代碼是:

  1. spin_lock_init(&base->lock);
  2. for (j = 0; j < TVN_SIZE; j++) {
  3. INIT_LIST_HEAD(base->tv5.vec + j);
  4. INIT_LIST_HEAD(base->tv4.vec + j);
  5. INIT_LIST_HEAD(base->tv3.vec + j);
  6. INIT_LIST_HEAD(base->tv2.vec + j);
  7. }
  8. for (j = 0; j < TVR_SIZE; j++)
  9. INIT_LIST_HEAD(base->tv1.vec + j);
  10. base->timer_jiffies = jiffies;
  11. base->next_timer = base->timer_jiffies;

這段代碼的主體是base,base的定義是:structtvec_base *base;

這個tvec_base是動態定時器的主要數據結構,每個cpu上有一個,它包含相應cpu中處理動態定時器需要的所有數據。為簡化分析僅考慮單cpu。給出這個數據機構:

  1. struct tvec_base {
  2. spinlock_t lock;
  3. struct timer_list *running_timer;
  4. unsigned long timer_jiffies;
  5. unsigned long next_timer;
  6. struct tvec_root tv1;
  7. struct tvec tv2;
  8. struct tvec tv3;
  9. struct tvec tv4;
  10. struct tvec tv5;
  11. } ____cacheline_aligned;

其中,timer_list是具體定時器的結構體(後面再具體看timer_list結構體);上面包含tv1,tv2,tv3,tv4,tv5;內核定時器的巧妙設計就在於此。

  1. #define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
  2. #define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
  3. #define TVN_SIZE (1 << TVN_BITS)
  4. #define TVR_SIZE (1 << TVR_BITS)
  5. #define TVN_MASK (TVN_SIZE - 1)
  6. #define TVR_MASK (TVR_SIZE - 1)
  7. struct tvec {
  8. struct list_head vec[TVN_SIZE];
  9. };
  10. struct tvec_root {
  11. struct list_head vec[TVR_SIZE];
  12. };

從這個定義看到,tv1就是長度為256的數組,數組成員是list_head;同樣的,tv2,tv3,tv4和tv5都是長度為64的數組,數組成員是list_head。List_head就是linux內核代碼中廣泛使用的雙向鏈表。在阻塞和非阻塞中的等待隊列時就看到了list_head的應用。那麼,tv1-tv5都是數組+鏈表的實現,其實hash的有一種簡單實現就是數組+鏈表的組合,那麼這幾個就有些hash的味道,具體是不是,還要分析道後面才知道。

再回到前面的初始化中,

for(j = 0; j < TVN_SIZE; j++) {

INIT_LIST_HEAD(base->tv5.vec+ j);

INIT_LIST_HEAD(base->tv4.vec+ j);

INIT_LIST_HEAD(base->tv3.vec+ j);

INIT_LIST_HEAD(base->tv2.vec+ j);

}

for(j = 0; j < TVR_SIZE; j++)

INIT_LIST_HEAD(base->tv1.vec+ j);

就tv1-tv5這5個結構體中的數組中每個list_head進行初始化。

base->timer_jiffies= jiffies;

base->next_timer= base->timer_jiffies;

將base中的timer_jiffies和next_timer都初始化為jiffies。


初始化完成後,在init_timers函數的第二個重要的步驟是:

open_softirq(TIMER_SOFTIRQ,run_timer_softirq);

這個函數注冊定時器軟中斷,簡單的軟中斷分析見《Linux的軟中斷》 見 http://www.linuxidc.com/Linux/2012-04/57918.htm


下面來看具體定時器的初始化和添加操作:

初始化的函數:

  1. #define init_timer(timer) \
  2. do { \
  3. static struct lock_class_key __key; \
  4. init_timer_key((timer), #timer, &__key); \
  5. } while (0)
  6. void init_timer_key(struct timer_list *timer,
  7. const char *name,
  8. struct lock_class_key *key)
  9. {
  10. debug_init(timer);
  11. __init_timer(timer, name, key);
  12. }
  13. static void __init_timer(struct timer_list *timer,
  14. const char *name,
  15. struct lock_class_key *key)
  16. {
  17. timer->entry.next = NULL;
  18. timer->base = __raw_get_cpu_var(tvec_bases);
  19. #ifdef CONFIG_TIMER_STATS
  20. timer->start_site = NULL;
  21. timer->start_pid = -1;
  22. memset(timer->start_comm, 0, TASK_COMM_LEN);
  23. #endif
  24. lockdep_init_map(&timer->lockdep_map, name, key, 0);
  25. }

初始化的宏定義:

  1. #define TIMER_INITIALIZER(_function, _expires, _data) { \
  2. .entry = { .prev = TIMER_ENTRY_STATIC }, \
  3. .function = (_function), \
  4. .expires = (_expires), \
  5. .data = (_data), \
  6. .base = &boot_tvec_bases, \
  7. __TIMER_LOCKDEP_MAP_INITIALIZER( \
  8. __FILE__ ":" __stringify(__LINE__)) \
  9. }

定時器的添加:

  1. void add_timer(struct timer_list *timer)
  2. {
  3. BUG_ON(timer_pending(timer));
  4. mod_timer(timer, timer->expires);
  5. }

Timer_list結構體的定義:

  1. struct timer_list {
  2. struct list_head entry;
  3. unsigned long expires;
  4. void (*function)(unsigned long);
  5. unsigned long data;
  6. struct tvec_base *base;
  7. #ifdef CONFIG_TIMER_STATS
  8. void *start_site;
  9. char start_comm[16];
  10. int start_pid;
  11. #endif
  12. #ifdef CONFIG_LOCKDEP
  13. struct lockdep_map lockdep_map;
  14. #endif
  15. };

  1. int mod_timer(struct timer_list *timer, unsigned long expires)
  2. {
  3. /*
  4. * This is a common optimization triggered by the
  5. * networking code - if the timer is re-modified
  6. * to be the same thing then just return:
  7. */
  8. if (timer_pending(timer) && timer->expires == expires)
  9. return 1;
  10. return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
  11. }
Copyright © Linux教程網 All Rights Reserved