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