zoukankan      html  css  js  c++  java
  • linux initcall 介绍 (转自http://blog.csdn.net/fenzhikeji/article/details/6860143)

    现在以module_init为例分析initcall在内核中的调用顺序

    在头文件init.h中,有如下定义:

    #define module_init(x)     __initcall(x);

    很明显,module_init()只是一个面具而已,揭开这个面具,下面藏着的是__initcall()

    __initcall()又是何方神圣呢?继续揭露真相:

    #define __initcall(fn) device_initcall(fn)

    藏得真深,继续看:

    #define device_initcall(fn)              __define_initcall("6",fn,6)

    #define __define_initcall(level,fn,id)

           static initcall_t __initcall_##fn##id __used

           __attribute__((__section__(".initcall" level ".init"))) = fn

    最终我们看到的是module_init的真身:__define_initcall(level,fn,id),仔细 推敲这个真身,知道这是个宏,它把传给module_init的函数名组装成以__initcall为前缀的、以6为后缀的函数名,并把这个函数定义到代 码段.initcall6.init里面。

    在代码段.initcall6.init里面?这函数躲在这里干嘛,啥时候才轮得到它出头啊!找到有此字符串的文件vmlinux.lds.h,相关代码如下所示:

    #define INITCALLS                                          

           *(.initcallearly.init)                                       

           VMLINUX_SYMBOL(__early_initcall_end) = .;                 

         *(.initcall0.init)                                      

         *(.initcall0s.init)                                    

         *(.initcall1.init)                                      

         *(.initcall1s.init)                                    

         *(.initcall2.init)                                      

         *(.initcall2s.init)                                    

         *(.initcall3.init)                                      

         *(.initcall3s.init)                                    

         *(.initcall4.init)                                      

         *(.initcall4s.init)                                    

         *(.initcall5.init)                                      

         *(.initcall5s.init)                                    

           *(.initcallrootfs.init)                                     

         *(.initcall6.init)                                      

         *(.initcall6s.init)                                    

         *(.initcall7.init)                                      

         *(.initcall7s.init)

    要命,又是一个陌生的宏,不过还好的是他样子看起来还不难看,而且好找规律,看看这是个什么样的东西呢?

    字符串.initcall6.init夹杂在这个宏的第n行,具体自己数,他们挨个挨个有顺序的组成一个整体,此整体又构成一个用大写字母写的宏INITCALLS,从气势看这个东西给人牛逼的感觉,这么神奇,那他在那里高就呢?

    坑爹的,踏破铁鞋无觅处,得来非常费工夫,他竟然在一个偏僻的vmlinux.lds.S里面!估计超出来好多童鞋可以 接受的范围吧,这还不算,这还是个汇编文件!哎,不管怎样,追根述源顺藤摸瓜找到了INITCALLS的娘家,却发现这是个完全陌生的世界!蛋蛋为此疼了 好久,最终还是鼓起来武松打虎的勇气依然闯了进去。人说绝望之后就会有希望,柳暗之后又是一村,哥哥我满眼噙着泪水的发现他们是有人情味的!这个激动啊, 不是三言两语可以说得清的,来看看INITCALLS她娘家房子咋样:

                  …………省略一大段………….

    __initcall_start = .;

                         INITCALLS

                  __initcall_end = .;

                  __con_initcall_start = .;

                         *(.con_initcall.init)

                  __con_initcall_end = .;

                  __security_initcall_start = .;

                         *(.security_initcall.init)

                  __security_initcall_end = .;

                  …………省略一大段……………

    是不是觉得这还是有点人道主义的,不会像阿拉伯为或藏文一样让你想跳楼吧,来认识一下它的三大姑二大婆吧,对于像 __initcall_start = .与__initcall_end = .之类狐假虎威的家伙咱们初来乍到时吃过他不少亏,印象是相当深刻的,一眼就瞅见它的衰样了,这里的小点不就是代表当前地址吗,一个等号不就是把点代表的 当前地址付给了左边的变量啦,这难不倒已经有两把刷子的我的,照此看来,估摸着__initcall_start与__initcall_end会有同伙 在.c文件里面和他们暗通款曲狼狈为奸,待会再好好戏耍它一番,先pass了,接着看看还有啥新鲜的,嗯?没了,还是回头吧,没苦我一般是不会自找来尝 的,甜头嘛另当别论啦,哈哈哈,

    言归正传,INITCALLS在__initcall_start = .与__initcall_end = .之间,表示INITCALLS宏内涵的相关段代码顺序存放在这里,module_init所代表段的镶嵌其中,等候挨个轮到自己被光顾,从 INITCALLS的内容看它被访问的时刻排得还是挺后的,那么其他的又是何方圣神呢?其看下面分解:

    #define pure_initcall(fn)          __define_initcall("0",fn,0)

     

    #define core_initcall(fn)          __define_initcall("1",fn,1)

    #define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)

    #define postcore_initcall(fn)           __define_initcall("2",fn,2)

    #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)

    #define arch_initcall(fn)          __define_initcall("3",fn,3)

    #define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)

    #define subsys_initcall(fn)              __define_initcall("4",fn,4)

    #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)

    #define fs_initcall(fn)                     __define_initcall("5",fn,5)

    #define fs_initcall_sync(fn)            __define_initcall("5s",fn,5s)

    #define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)

    #define device_initcall(fn)              __define_initcall("6",fn,6)

    #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)

    #define late_initcall(fn)           __define_initcall("7",fn,7)

    #define late_initcall_sync(fn)         __define_initcall("7s",fn,7s)

    至此我们应该明白了各个initcall是如何来的以及在代码存储空间上是怎么组织的了吧,下面来看看内核是什么时候调用它的。

    内核启动流程如下所示

    Main()àlinux_main()àstart_uml()àstart_kernel_proc()àstart_kernelàrest_inità kernel_inità do_basic_setupà do_initcalls

    do_initcalls的代码如下所示

    static void __init do_initcalls(void)

    {

           initcall_t *call;

     

           for (call = __early_initcall_end; call < __initcall_end; call++)

                  do_one_initcall(*call);

     

           /* Make sure there is no pending stuff from the initcall sequence */

           flush_scheduled_work();

    }

    上面的代码中,__early_initcall_end在INITCALLS内定义,__initcall_end在 文件vmlinux.lds.S中定义,他们代表的是一些初始化函数的指针数组起始与结束地址,执行函数do_initcalls时,包含在这各指针数组 里面的函数顺序的被调用以执行一些必要的初始化工作。至此,明白的各initcall的执行时刻了吧。

  • 相关阅读:
    创建并发布npm包
    ubuntu下python+tornado+supervisor+nginx部署
    Ubuntu下pycharm设定任务栏图标后打开出现问号图标
    Ubuntu下安装keras
    Windows和Ubuntu双系统
    Java获取精确到秒的时间戳
    Jmeter Java请求
    git 生成公钥、私钥方法与clone使用方法
    Oracle 安全管理
    五、python沉淀之路--字典
  • 原文地址:https://www.cnblogs.com/zxc2man/p/4435257.html
Copyright © 2011-2022 走看看