Linux内核中的初始化initcall_t

基于Linux 2.6.32

include\asm-generic\Vmlinux.lds.h中有如下定义:

这等于是安排了名称如.initcall<level>[s].init的一系列section的顺序,level越小,越靠前。

符号__initcall_start记录了这片区域的开始,__initcall_end符号记录了这片区域的结束。

__early_initcall_end则将这片区域更进一步分成了两段。

  1. #define INITCALLS                           \  
  1.     *(.initcallearly.init)                      \  
  1.     VMLINUX_SYMBOL(__early_initcall_end) = .;           \  
  1.     *(.initcall0.init)                      \  
  1.     *(.initcall0s.init)                     \  
  1.     *(.initcall1.init)                      \  
  1.     *(.initcall1s.init)                     \  
  1.     *(.initcall2.init)                      \  
  1.     *(.initcall2s.init)                     \  
  1.     *(.initcall3.init)                      \  
  1.     *(.initcall3s.init)                     \  
  1.     *(.initcall4.init)                      \  
  2.     *(.initcall4s.init)                     \  
  3.     *(.initcall5.init)                      \  
  1.     *(.initcall5s.init)                     \  
  1.     *(.initcallrootfs.init)                     \  
  1.     *(.initcall6.init)                      \  
  1.     *(.initcall6s.init)                     \  
  1.     *(.initcall7.init)                      \  
  1.     *(.initcall7s.init)  
  2.   
  1. #define INIT_CALLS                          \  
  1.         VMLINUX_SYMBOL(__initcall_start) = .;           \  
  1.         INITCALLS                       \  
  1.         VMLINUX_SYMBOL(__initcall_end) = .;  

 

下面来看看,这些section里面究竟是什么内容。

以pci_driver_init函数为例(位于drivers/pci/pci-driver.c)。

 

  1. static int __init pci_driver_init(void)  
  1. {  
  1.     return bus_register(&pci_bus_type);  
  1. }  
  1.   
  1.   
  1. postcore_initcall(pci_driver_init); 

 

可见函数下面跟了一个postcore_initcall宏的调用,追踪宏的定义,得到如下代码。

 

  1. #define postcore_initcall(fn)       __define_initcall("2",fn,2)  
  1. #define __define_initcall(level,fn,id) \  
  1.     static initcall_t __initcall_##fn##id __used \  
  2.     __attribute__((__section__(".initcall" level ".init"))) = fn  

 

这样的话,postcore_initcall(pci_driver_init);展开后,其实就是如下内容

 

  1. static initcall_t __initcall_pci_driver_init2 __attribute__((__used__)) \  
  1.     __attribute__((__section__(".initcall2.init"))) = pci_driver_init;  

 

而initcall_t实际上是个函数指针类型,定义如下

typedef int (*initcall_t)(void);

 

这样的话,上面的宏展开后,其实就是定义了一个变量__initcall_pci_driver_init2,他是一个函数指针,指向pci_driver_init。这个变量被链接到名为.initcall2.init的section中。

 

当然,内核中,还有如下一些和postcore_initcall类似的宏(位于include/linux/init.h)。

调用这些宏,就会产生相应的函数指针变量,这些变量则被链接到相应的名称.initcall<level>[s].initsection中去。

 

  1. #define pure_initcall(fn)       __define_initcall("0",fn,0)  
  1.   
  1. #define core_initcall(fn)       __define_initcall("1",fn,1)  
  1. #define core_initcall_sync(fn)      __define_initcall("1s",fn,1s)  
  1. #define postcore_initcall(fn)       __define_initcall("2",fn,2)  
  1. #define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)  
  1. #define arch_initcall(fn)       __define_initcall("3",fn,3)  
  1. #define arch_initcall_sync(fn)      __define_initcall("3s",fn,3s)  
  1. #define subsys_initcall(fn)     __define_initcall("4",fn,4)  
  1. #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)  
  1. #define fs_initcall(fn)         __define_initcall("5",fn,5)  
  1. #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)  
  1. #define rootfs_initcall(fn)     __define_initcall("rootfs",fn,rootfs)  
  1. #define device_initcall(fn)     __define_initcall("6",fn,6)  
  2. #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)  
  3. #define late_initcall(fn)       __define_initcall("7",fn,7)  
  4. #define late_initcall_sync(fn)      __define_initcall("7s",fn,7s)  

 

下面的问题来了,这些函数指针如何被调用呢?接着往下看。

内核初始化时,kernel_init函数(位于init/main.c)会依次执行到如下函数,完成这些初始化函数的调用。

可见,调用顺序是,level越小的section中的函数指针,越先被调用。

 

  1. static void __init do_pre_smp_initcalls(void)  
  2. {  
  3.     initcall_t *call;  
  4.   
  5.     for (call = __initcall_start; call < __early_initcall_end; call++)  
  6.         do_one_initcall(*call);  
  7. }  

 

  1. static void __init do_initcalls(void)  
  2. {  
  3.     initcall_t *call;  
  4.   
  5.     for (call = __early_initcall_end; call < __initcall_end; call++)  
  6.         do_one_initcall(*call);  
  7.   
  8.     /* Make sure there is no pending stuff from the initcall sequence */  
  9.     flush_scheduled_work();  
  10. }  

 

源文档 <http://blog.csdn.net/crazycoder8848/article/details/50847013

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值