http://www.ibm.com/developerworks/cn/linux/l-cn-timerm/?S_TACT=105AGX52&S_CMP=reg-ccid
http://blog.youkuaiyun.com/dog250/article/details/5303566
http://www.ibm.com/developerworks/cn/linux/l-cn-clocks/
先搞清楚两个概念:
超时:表示将在一段时间之后发生的事件,但可以且通常都会在发生之前取消,如:网络传输超时的设置。分辨率对超时定时器并不是很重要。
定时器:用于实现时序。使用 timer 类型的定时器往往要求在精确的时钟条件下完成特定的事件,通常是周期性的并且依赖超时机制进行处理。例如设备驱动通常会定时读写设备
来进行数据交互。
/** * __run_timers - run all expired timers (if any) on this CPU. * @base: the timer vector to be processed. * * This function cascades all vectors and executes all expired timer * vectors. */ static inline void __run_timers(struct tvec_base *base) { struct timer_list *timer; spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->timer_jiffies)) { //处理所有从时间点timer_jiffies 到 时间点jiffies的事件。 struct list_head work_list; struct list_head *head = &work_list; int index = base->timer_jiffies & TVR_MASK; //计算第一组的索引位置 /* * Cascade timers: */ if (!index && (!cascade(base, &base->tv2, INDEX(0))) && //cascade用于从指定组取得定时器补充前一组。 (!cascade(base, &base->tv3, INDEX(1))) && !cascade(base, &base->tv4, INDEX(2))) cascade(base, &base->tv5, INDEX(3)); //如果前组都已经是空的了,那么就将第五组的向前移动(因为第五组的时间到期时间实在是太晚,因此一般都不会东它们。) ++base->timer_jiffies; //timer_jiffiers记录的是一个时间点,这个时间点之前到期的定时器都已经处理过了。 list_replace_init(base->tv1.vec + index, &work_list); //第一组位于索引位置的所有定时器都转移到一个临时链表中,从原来的数据结构中删除。 while (!list_empty(head)) { //分别执行各个定时器的处理程序 void (*fn)(unsigned long); unsigned long data; timer = list_first_entry(head, struct timer_list,entry); fn = timer->function; data = timer->data; timer_stats_account_timer(timer); base->running_timer = timer; detach_timer(timer, 1); spin_unlock_irq(&base->lock); call_timer_fn(timer, fn, data); spin_lock_irq(&base->lock); } } base->running_timer = NULL; spin_unlock_irq(&base->lock); } struct timer_list { /* * All fields that change during normal runtime grouped to the * same cacheline */ struct list_head entry; unsigned long expires; struct tvec_base *base; void (*function)(unsigned long); unsigned long data; int slack; #ifdef CONFIG_TIMER_STATS int start_pid; void *start_site; char start_comm[16]; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }; 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;
asmlinkage void __init start_kernel(void) { tick_init(); init_timers(); hrtimers_init(); softirq_init(); timekeeping_init(); time_init(); profile_init(); if (late_time_init) late_time_init(); sched_clock_init(); }