/*
软件时钟可分为两种类型:
仅仅激活一次
激活多次或者周期性激活
多次激活的实现机制就是要在软件时钟处理函数中重新设置软件时钟的到期时间为将来的一个时间,
这个过程通过调用 mod_timer 函数来实现.
*/
/*
从上面的说明中可以看出:
软件时钟是按照其到期时间相对于当前正在处理的软件时钟的到期时间
( timer_jiffies 的数值)保存在 struct tvec_base 变量中的。
而且这个到期时间的最大相对值(到期时间 - timer_jiffies )为 0xffffffffUL
( tv5 最后一个元素能够表示的相对到期时间的最大值)。
注:一个tick的长度指的是两次硬件时钟中断发生之间的时间间隔
*/
/*
这里所说“软件时钟”指的是软件定时器( Software Timers ),
是一个软件上的概念,是建立在硬件时钟基础之上的。
它记录了未来某一时刻要执行的操作(函数),
并使得当这一时刻真正到来时,这些操作(函数)能够被按时执行
实现软件时钟原理也比较简单:
每一次硬件时钟中断到达时,内核更新的 jiffies ,
然后将其和软件时钟的到期时间进行比较。
如果 jiffies 等于或者大于软件时钟的到期时间,
内核就执行软件时钟指定的函数。
*/
u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
/*
* per-CPU timer vector definitions:
*/
#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8)
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
/*
可见它们实际上就是类型为 struct list_head 的数组,
其中 TVN_SIZE 和 TVR_SIZE 在系统没有配置宏 CONFIG_BASE_SMALL 时分别被定义为64和256。
*/
struct tvec {
struct list_head vec[TVN_SIZE];
};
struct tvec_root {
struct list_head vec[TVR_SIZE];
};
//软件时钟,记录了软件时钟的到期时间以及到期后要执行的操作。
struct timer_list {
struct list_head entry; //所在的链表
unsigned long expires; //到期时间
void (*function)(unsigned long); //回调函数,到期后执行的操作
unsigned long data; //回调函数的参数
struct tvec_base *base; //记录该软件时钟所在的 struct tvec_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
};
/*
从图中可以清楚地看出:
软件时钟( struct timer_list ,在图中由 timer 表示)以双向链表( struct list_head )的形式,
按照它们的到期时间保存相应的桶( tv1~tv5 )中。
tv1 中保存了相对于 timer_jiffies 下256个 tick 时间内到期的所有软件时钟;
tv2 中保存了相对于 timer_jiffies 下256*64个 tick 时间内到期的所有软件时钟;
tv3 中保存了相对于 timer_jiffies 下256*64*64个 tick 时间内到期的所有软件时钟;
tv4 中保存了相对于 timer_jiffies 下256*64*64*64个 tick 时间内到期的所有软件时钟;
tv5 中保存了相对于 timer_jiffies 下256*64*64*64*64个 tick 时间内到期的所有软件时钟。
具体的说,从静态的角度看,假设 timer_jiffies 为0,
那么 tv1[0] 保存着当前到期(到期时间等于 timer_jiffies )的软件时钟(需要马上被处理),
tv1[1] 保存着下一个 tick 到达时,到期的所有软件时钟,
tv1[n] (0<= n <=255)保存着下 n 个 tick 到达时,到期的所有软件时钟。
而 tv2[0] 则保存着下256到511个 tick 之间到期所有软件时钟,
tv2[1] 保存着下512到767个 tick 之间到期的所有软件时钟,
tv2[n] (0<= n <=63)保存着下256*(n+1)到256*(n+2)-1个 tick 之间到达的所有软件时钟。
tv3~tv5 依次类推。
TV1 为第一个timer 数组,其中存放着从
timer_jiffies(当前到期的jiffies)到timer_jiffies + 255 共256 个tick 对应的timer list。
TV2 有64 个单元,每个单元都对应着
256 个tick,因此TV2 所表示的超时时间范围从timer_jiffies + 256 到timer_jiffies + 256 *
64 – 1
还需要注意的是软件时钟的处理是局部于 CPU 的,
所以在 SMP 系统中每一个 CPU 都保存一个类型为 struct tvec_base 的变量,
用来组织、管理本 CPU 的软件时钟。
从图中也可以看出 struct tvec_base 变量是 per-CPU 的
*/
struct tvec_base {
spinlock_t lock;
struct timer_list *running_timer; //正在处理的软件时钟
unsigned long timer_jiffies; //当前正在处理的软件时钟到期时间
unsigned long next_timer;
struct tvec_root tv1; //保存了到期时间从 timer_jiffies 到 timer_jiffies + 2^8-1之间(包括边缘值)的所有软件时钟
struct tvec tv2; //保存了到期时间从 timer_jiffies + 2^8到 timer_jiffies +2^14-1之间(包括边缘值)的 所有软件时钟
struct tvec tv3; //从 timer_jiffies +2^14到 timer_jiffies +2^20-1之间(包括边缘值)的所有软件时钟
struct tvec tv4; //从 timer_jiffies +2^20到 timer_jiffies +2^26-1之间(包括边缘值)的所有软件时钟
struct tvec tv5; //从 timer_jiffies &#