看了好多人分析了软件时钟部分,我也凑一下热闹吧,
之前有说道软件时钟在何处执行的,在系统时钟中断里,执行的函数
在init_timers中定义了open_softirq(TIMER_SOFTIRQ, run_timer_softirq); //初始化软中断函数 主意这里的是定时器软中断,开来还有其他软中断啊
void open_softirq(int nr, void (*action)(struct softirq_action *)) //初始化软中断函数
{
softirq_vec[nr].action = action;
}
/kernel/softirq.c
static struct softirq_action softirq_vec[NR_SOFTIRQS]
/include/linux/interrupt.h
struct softirq_action
{
void (*action)(struct softirq_action *);
};
这里代表哪些中断需要被调用的函数
这里的run_timer_softirq就是执行的函数,他遍历软中断链表,一个一个找,执行相应的中断
/kernel/timer.c
static void run_timer_softirq(struct softirq_action *h)
{
struct tvec_base *base = __get_cpu_var(tvec_bases);
perf_counter_do_pending();
hrtimer_run_pending();
if (time_after_eq(jiffies, base->timer_jiffies))
__run_timers(base);
}
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)) {
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(base, &base->tv3, INDEX(1))) &&
!cascade(base, &base->tv4, INDEX(2)))
cascade(base, &base->tv5, INDEX(3));
++base->timer_jiffies; //
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);
set_running_timer(base, timer);
detach_timer(timer, 1);
spin_unlock_irq(&base->lock);
{
int preempt_count = preempt_count();
#ifdef CONFIG_LOCKDEP
/*
* It is permissible to free the timer from
* inside the function that is called from
* it, this we need to take into account for
* lockdep too. To avoid bogus "held lock
* freed" warnings as well as problems when
* looking into timer->lockdep_map, make a
* copy and use that here.
*/
struct lockdep_map lockdep_map =
timer->lockdep_map;
#endif
/*
* Couple the lock chain with the lock chain at
* del_timer_sync() by acquiring the lock_map
* around the fn() call here and in
* del_timer_sync().
*/
lock_map_acquire(&lockdep_map);
fn(data);
lock_map_release(&lockdep_map);
if (preempt_count != preempt_count()) {
printk(KERN_ERR "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);
spin_unlock_irq(&base->lock);
}
再贴一下struct tvec_base吧,孰能生巧
/kernel/timer.c
struct tvec_base {
spinlock_t lock;
struct timer_list *running_timer;
unsigned long timer_jiffies;
struct tvec_root tv1;
struct tvec tv2; ///不同时间的软件定时操作
struct tvec tv3;
struct tvec tv4;
struct tvec tv5;
} ____cacheline_aligned;
struct tvec {
struct list_head vec[TVN_SIZE];
};
可以看出这个softirq_vec里存放了许多软件定时操作啊,
下面说一下具体的操作
/include/linux/timer.h
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
};
首先定义一个struct timer_list实例,然后调用add_timer就ok了,
如果想删掉,则调用del_timer。支持结束