linux内核中的定时器代码简介

时间:2022-04-17 00:15:12

    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)