其他的部分我们忽略,我们就发现定时器模块会调用init_timers_cpu来初始化.我们来分析这个函数.
这个函数最主要的功能就是初始化boot_tvec_bases,也就是全局的定时器表:
Java代码
static int __cpuinit init_timers_cpu(int cpu) { int j; struct tvec_base *base; ///可以看到这个是一个静态变量.它保存了每个cpu上的那个boot_tvec_bases. static char __cpuinitdata tvec_base_done[NR_CPUS]; ///如果为空,说明这个cpu上的定时器表还没有初始化,因此需要初始化 if (!tvec_base_done[cpu]) { /*这个也是一个静态变量.它表示了cpu是否初始化完毕.这个函数有一个宏__cpuinit,这个将 *这个函数放置到cpuinit这个段,因此也就是说这个函数会先在cpu初始化时调用,也就是第一**次会先给boot_done赋值,然后再调用这个函数才会进入kmalloc. */ static char boot_done; if (boot_done) { /* * The APs use this path later in boot */ ///malloc一个tvec_base 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的,只有boot_tvec_bases,因此,也就是将base这个指针付给boot_tvec_bases. per_cpu(tvec_bases, cpu) = base; } else { ///cpu初始化完毕后会进入这里,标记了cpu已经boot完毕.此时内存初始化完毕. boot_done = 1; base = &boot_tvec_bases; } tvec_base_done[cpu] = 1; } else { ///取出tvec_base付给base 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; return 0; }