我是靠谱客的博主 凶狠芒果,最近开发中收集的这篇文章主要介绍init_timers();,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

void __init init_timers(void)
{
//初始化本 CPU 上的软件时钟相关的数据结构
	int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
				(void *)(long)smp_processor_id()); //因为是初始化阶段,所以得到的CPU为启动CPU

	init_timer_stats();

	BUG_ON(err != NOTIFY_OK);
//向 cpu_chain 通知链注册元素 timers_nb ,该元素的回调函数用于初始化指定 CPU 上的软件时钟相关的数据结构
	register_cpu_notifier(&timers_nb);
//初始化时钟的软中断处理函数
	open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}

这个函数完成的主要作用包括:

(1)初始化本 CPU 上的软件时钟相关的数据结构;

(2)向 cpu_chain 通知链注册元素 timers_nb ,该元素的回调函数用于初始化指定 CPU 上的软件时钟相关的数据结构;

(3)初始化时钟的软中断处理函数。

对于操作(1):

static int __cpuinit timer_cpu_notify(struct notifier_block *self,
				unsigned long action, void *hcpu)
{
	long cpu = (long)hcpu;
	int err;

	switch(action) {
	case CPU_UP_PREPARE:
	case CPU_UP_PREPARE_FROZEN:
		err = init_timers_cpu(cpu);  //调用该函数,参数CPU即为启动CPU(或者主CPU)
		if (err < 0)
			return notifier_from_errno(err);
		break;
#ifdef CONFIG_HOTPLUG_CPU
	case CPU_DEAD:
	case CPU_DEAD_FROZEN:
		migrate_timers(cpu);
		break;
#endif
	default:
		break;
	}
	return NOTIFY_OK;
}

调用init_timers_cpu:


static int __cpuinit init_timers_cpu(int cpu)
{
    int j;
    struct tvec_base *base;
    static char __cpuinitdata tvec_base_done[NR_CPUS];

    if (!tvec_base_done[cpu]) {                                        //启动CPU尚未进行tvec的设置
        static char boot_done;

        if (boot_done) {
            /*
             * The APs use this path later in boot
             */
            base = kmalloc_node(sizeof(*base),
                        GFP_KERNEL | __GFP_ZERO,
                        cpu_to_node(cpu));
            if (!base)
                return -ENOMEM;

            /* Make sure that tvec_base is 2 byte aligned */
            if (tbase_get_deferrable(base)) {
                WARN_ON(1);
                kfree(base);
                return -ENOMEM;
            }
            per_cpu(tvec_bases, cpu) = base;
        } else {                                                         //第一次进行设置
            /*
             * This is for the boot CPU - we use compile-time
             * static initialisation because per-cpu memory isn't
             * ready yet and because the memory allocators are not
             * initialised either.
             */
            boot_done = 1;
            base = &boot_tvec_bases;
        }
        tvec_base_done[cpu] = 1;
    } else {
        base = per_cpu(tvec_bases, cpu);
    }

    spin_lock_init(&base->lock);

//开始初始化5个定时器表

    for (j = 0; j < TVN_SIZE; j++) {
        INIT_LIST_HEAD(base->tv5.vec + j);
        INIT_LIST_HEAD(base->tv4.vec + j);
        INIT_LIST_HEAD(base->tv3.vec + j);
        INIT_LIST_HEAD(base->tv2.vec + j);
    }
    for (j = 0; j < TVR_SIZE; j++)
        INIT_LIST_HEAD(base->tv1.vec + j);


//默认值为初始化时的jiffes
    base->timer_jiffies = jiffies; //当前正在处理的软件时钟到期时间 
    base->next_timer = base->timer_jiffies;
    return 0;
}

对于操作(3),open_softirq(TIMER_SOFTIRQ, run_timer_softirq):

void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}

我们看到,定时器软中断所对应的action是run_timer_softirq,也就是当时钟中断到来,软中断启动时,就会调用这个函数,我们来看一下这个函数:

 
/*
 * This function runs timers and the timer-tq in bottom half context.
 */
static void run_timer_softirq(struct softirq_action *h)
{
	struct tvec_base *base = __this_cpu_read(tvec_bases);

	hrtimer_run_pending();

//判断当前的jiffies是否大于等于最小的那个超时jiffies.是的话就进入定时器处理
	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(struct tvec_base *base)  
    {  
        struct timer_list *timer;  
      
        spin_lock_irq(&base->lock);  
        while (time_after_eq(jiffies, base->timer_jiffies)) {  //处理所有从时间点timer_jiffies 到 时间点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用于从指定组取得定时器补充前一组。  
                    (!cascade(base, &base->tv3, INDEX(1))) &&  
                        !cascade(base, &base->tv4, INDEX(2)))  
                cascade(base, &base->tv5, INDEX(3));                    //如果前组都已经是空的了,那么就将第五组的向前移动(因为第五组的时间到期时间实在是太晚,因此一般都不会东它们。)      
            ++base->timer_jiffies;                 //timer_jiffiers记录的是一个时间点,这个时间点之前到期的定时器都已经处理过了。  
            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);  
      
                base->running_timer = timer;  
                detach_timer(timer, 1);  
      
                spin_unlock_irq(&base->lock);  
                call_timer_fn(timer, fn, data);  
                spin_lock_irq(&base->lock);  
            }  
        }  
        base->running_timer = NULL;  
        spin_unlock_irq(&base->lock);  
    }  
  




最后

以上就是凶狠芒果为你收集整理的init_timers();的全部内容,希望文章能够帮你解决init_timers();所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部