时钟五

看了好多人分析了软件时钟部分,我也凑一下热闹吧,

之前有说道软件时钟在何处执行的,在系统时钟中断里,执行的函数

在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。支持结束


 

 

 


 

你可能感兴趣的:(时钟五)