native_init_IRQ结束后,init_IRQ也就结束了,回到start_kernel中,607行,prio_tree_init函数很简单:
void __init prio_tree_init(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(index_bits_to_maxindex) - 1; i++)
index_bits_to_maxindex[i] = (1UL << (i + 1)) - 1;
index_bits_to_maxindex[ARRAY_SIZE(index_bits_to_maxindex) - 1] = ~0UL;
}
初始化全局变量index_bits_to_maxindex[]数组,不在话下。继续走,608行,init_timers,来自kernel/timer.c:
1736void __init init_timers(void)
1737{
1738 int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
1739 (void *)(long)smp_processor_id());
1740
1741 init_timer_stats();
1742
1743 BUG_ON(err != NOTIFY_OK);
1744 register_cpu_notifier(&timers_nb);
1745 open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
1746}
init_timers函数首先1738初始化本地CPU上的软时钟相关的数据结构,该结构是一个notifier_block类型全局变量,定义在kernel/time.c:
static struct notifier_block __cpuinitdata timers_nb = {
.notifier_call = timer_cpu_notify,
};
timers_nb的回调函数timer_cpu_notify用于初始化指定CPU上的软时钟相关的数据结构:
static int __cpuinit timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;
switch(action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (init_timers_cpu(cpu) < 0)
return NOTIFY_BAD;
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
case CPU_DEAD_FROZEN:
migrate_timers(cpu);
break;
#endif
default:
break;
}
return NOTIFY_OK;
}
我们指定的是CPU_UP_PREPARE,所以肯定执行init_timers_cpu(cpu):
1513static int __cpuinit init_timers_cpu(int cpu)
1514{
1515 int j;
1516 struct tvec_base *base;
1517 static char __cpuinitdata tvec_base_done[NR_CPUS];
1518
1519 if (!tvec_base_done[cpu]) {
1520 static char boot_done;
1521
1522 if (boot_done) {
1523 /*
1524 * The APs use this path later in boot
1525 */
1526 base = kmalloc_node(sizeof(*base),
1527 GFP_KERNEL | __GFP_ZERO,
1528 cpu_to_node(cpu));
1529 if (!base)
1530 return -ENOMEM;
1531
1532 /* Make sure that tvec_base is 2 byte aligned */
1533 if (tbase_get_deferrable(base)) {
1534 WARN_ON(1);
1535 kfree(base);
1536 return -ENOMEM;
1537 }
1538 per_cpu(tvec_bases, cpu) = base;
1539 } else {
1540 /*
1541 * This is for the boot CPU - we use compile-time
1542 * static initialisation because per-cpu memory isn't
1543 * ready yet and because the memory allocators are not
1544 * initialised either.
1545 */
1546 boot_done = 1;
1547 base = &boot_tvec_bases;
1548 }
1549 tvec_base_done[cpu] = 1;
1550 } else {
1551 base = per_cpu(tvec_bases, cpu);
1552 }
1553
1554 spin_lock_init(&base->lock);
1555
1556 for (j = 0; j < TVN_SIZE; j++) {
1557 INIT_LIST_HEAD(base->tv5.vec + j);
1558 INIT_LIST_HEAD(base->tv4.vec + j);
1559 INIT_LIST_HEAD(base->tv3.vec + j);
1560 INIT_LIST_HEAD(base->tv2.vec + j);
1561 }
1562 for (j = 0; j < TVR_SIZE; j++)
1563 INIT_LIST_HEAD(base->tv1.vec + j);
1564
1565 base->timer_jiffies = jiffies;
1566 base->next_timer = base->timer_jiffies;
1567 return 0;
1568}
1517定义个全局变量tvec_base_done[]数组,每个元素对应一个CPU的软时钟初始化状态。随后1519~1552行创建本地软时钟数据结构tvec_base。该结构定义如下:
struct tvec_base {
spinlock_t lock;
struct timer_list *running_timer;
unsigned long timer_jiffies;
unsigned long next_timer;
struct tvec_root tv1;
struct tvec tv2;
struct tvec tv3;
struct tvec tv4;
struct tvec tv5;
} ____cacheline_aligned;
然后1556~1566行初始化这个tvec_base结构。我们看到,最重要的是1565行,tvec_base结构的timer_jiffies字段被设置成了超级重要的jiffies宏,即自系统启动以来产生的节拍的总数,通过如下函数获得(本质上是一个汇编指令syscall):
# define jiffies raid6_jiffies()
static inline uint32_t raid6_jiffies(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + tv.tv_usec/1000;
}
static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
{
int ret;
asm volatile("syscall"
: "=a" (ret)
: "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
: __syscall_clobber );
return ret;
}
回到init_timers,当初始化了本地CPU上的软时钟数据结构之后,1741行,调用init_timer_stats,初始化每CPU变量tstats_lookup_lock作为自旋锁。然后1744行调用我们已经见过的register_cpu_notifier函数,将新建的这个timers_nb结构挂到全局cpu_chain链中,作为通知链注册。
最后,1655行,调用open_softirq初始化时钟的软中断处理函数:
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
软中断的概念如果还不熟悉的,请参考博客“下半部分”
http://blog.csdn.net/yunsongice/archive/2010/03/07/5354011.aspx