非淡泊无以明志,非宁静无以致远
分类: LINUX
2011-02-28 20:34:45
struct timer_list :软件时钟,记录了软件时钟的到期时间以及到期后要执行的操作。具体的成员以及含义见表3-1。
struct tvec_base :用于组织、管理软件时钟的结构。在 SMP 系统中,每个 CPU 有一个。具体的成员以及含义参见表3-2。
表3-1 struct timer_list 主要成员
域名 类型 描述
entry struct list_head 所在的链表
expires unsigned long 到期时间,以 tick 为单位
function void (*)(unsigned long) 回调函数,到期后执行的操作
data unsigned long 回调函数的参数
base struct tvec_base * 记录该软件时钟所在的 struct tvec_base 变量
表3-2 struct tvec_base 类型的成员
域名 类型 描述
lock spinlock_t 用于同步操作
running_timer struct timer_list * 正在处理的软件时钟
timer_jiffies unsigned long 当前正在处理的软件时钟到期时间
tv1 struct tvec_root 保存了到期时间从 timer_jiffies 到 timer_jiffies + 浅析Linux 时钟处理机制(图二)之间(包括边缘值)的所有软件时钟
tv2 struct tvec 保存了到期时间从 timer_jiffies + 浅析Linux 时钟处理机制(图三)到 timer_jiffies +浅析Linux 时钟处理机制(图四)之间(包括边缘值)的 所有软件时钟
tv3 struct tvec 保存了到期时间从 timer_jiffies +浅析Linux 时钟处理机制(图五)到 timer_jiffies +浅析Linux 时钟处理机制(图六)之间(包括边缘值)的所有软件时钟
tv4 struct tvec 保存了到期时间从 timer_jiffies +浅析Linux 时钟处理机制(图七)到 timer_jiffies +浅析Linux 时钟处理机制(图八)之间(包括边缘值)的所有软件时钟
tv5 struct tvec 保存了到期时间从 timer_jiffies +浅析Linux 时钟处理机制(图九)到 timer_jiffies +浅析Linux 时钟处理机制(图十)之间(包括边缘值)的所有软件时钟
其中 tv1 的类型为 struct tvec_root ,tv 2~ tv 5的类型为 struct tvec ,清单3-1显示它们的定义
清单3-1 struct tvec_root 和 struct tvec 的定义
struct tvec {
struct list_head vec[TVN_SIZE];
};
struct tvec_root {
struct list_head vec[TVR_SIZE];
};
可见它们实际上就是类型为 struct list_head 的数组,其中 TVN_SIZE 和 TVR_SIZE 在系统没有配置宏 CONFIG_BASE_SMALL 时分别被定义为64和256。
/*
* This function runs timers and the timer-tq in bottom half context.
*/
static void run_timer_softirq(struct softirq_action *h)
{
tvec_base_t *base = __get_cpu_var(tvec_bases);
hrtimer_run_queues();
//首先在软中断处理中判断jiffies如果大于最近的定时器的到期时间base->timer_jiffies,就表示有定时器到期了
//进入__run_timers(base)进行处理
if (time_after_eq(jiffies, base->timer_jiffies))
__run_timers(base);
}
/**
* __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(tvec_base_t *base)
{
struct timer_list *timer;
spin_lock_irq(&base->lock);
//判断jiffies是否大于当前定时器到期时间base->timer_jiffies,
//base->timer_jiffies也就是到期时间最短的那个
while (time_after_eq(jiffies, base->timer_jiffies)) {
struct list_head work_list;
struct list_head *head = &work_list;
//最近定时器在tv1中的index,也就是jiffies的低6位
int index = base->timer_jiffies & TVR_MASK;
/*
* Cascade timers:
*/
//如果tv1中index==0,表示tv1中定时器全部过时了,需要从tv2~tv5中取出256个jiffies的定时器填充tv1
//也就是说每过256个tick,就会cascade一次,下面再介绍cascade
if (!index &&
(!cascade(base, &base->tv2, INDEX(0))) &&
(!cascade(base, &base->tv3, INDEX(1))) &&
!cascade(base, &base->tv4, INDEX(2)))
cascade(base, &base->tv5, INDEX(3));
//为什么加1?
++base->timer_jiffies;
//tv1在index位置的定时器队列,用work_list指向它,并把tv1中index的队列头设为空
list_replace_init(base->tv1.vec + index, &work_list);
//如果取出的定时器队列不为空,需要处理定时器
while (!list_empty(head)) {
void (*fn)(unsigned long);
unsigned long data;
//找第一个timer
timer = list_first_entry(head, struct timer_list,entry);
fn = timer->function;
data = timer->data;
timer_stats_account_timer(timer);
set_running_timer(base, timer); //设为正在运行的timer
detach_timer(timer, 1); //删除这个timer
spin_unlock_irq(&base->lock); //在执行timer回调函数时,先释放lock
{
int preempt_count = preempt_count();
fn(data); //执行timer的函数
if (preempt_count != preempt_count()) {
printk(KERN_WARNING "huh, entered %p "
"with preempt_count %08x, exited"
" with %08x?\n",
fn, preempt_count,
preempt_count());
BUG();
}
}
spin_lock_irq(&base->lock);
}
}
set_running_timer(base, NULL); //把正在运行的timer设为空
spin_unlock_irq(&base->lock);
}
//取出tv2~tv5的定时器,放到tv1中
static int cascade(tvec_base_t *base, tvec_t *tv, int index)
{
/* cascade all the timers from tv up one level */
struct timer_list *timer, *tmp;
struct list_head tv_list;
list_replace_init(tv->vec + index, &tv_list);
/*
* We are removing _all_ timers from the list, so we
* don't have to detach them individually.
*/
list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
BUG_ON(tbase_get_base(timer->base) != base);
internal_add_timer(base, timer);
}
return index;
}
//tv2对应INDEX(0),即(jiffies>>8)&0x3f
//tv3对应INDEX(1),即(jiffies>>14)&0x3f
//tv4对应INDEX(2),即(jiffies>>20)&0x3f
//tv5对应INDEX(3),即(jiffies>>26)&0x3f
#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)