• 神秘的subsys_initcall【转】


    转自:http://blog.chinaunix.net/uid-12567959-id-161015.html

    在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢?让我们来揭开它的神秘面纱。

    先来看一段代码:

    ---------------------------------------------------------------------

    include/linux/init.h

    174 /*

    175  * Early initcalls run before initializing SMP.

    176  *

    177  * Only for built-in code, not modules.

    178  */

    179 #define early_initcall(fn)    __define_initcall("early",fn,early)

    180

    181 /*

    182  * A "pure" initcall has no dependencies on anything else, and purely

    183  * initializes variables that couldn't be statically initialized.

    184  *

    185  * This only exists for built-in code, not for modules.

    186  */

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

    188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ---------------------------------------------------------------------

    类似于subsys_initcall()还有很多,但它们都依赖于__define_initcall(),再来看__define_initcall()的定义:

    ---------------------------------------------------------------------

    include/linux/init.h

    131 typedef int (*initcall_t)(void);

    165  *

    166  * The `id' arg to __define_initcall() is needed so that multiple

    167  * initcalls can point at the same handler without causing duplicate-symbol build errors.

    168  */

    169

    170 #define __define_initcall(level,fn,id)

    171       static initcall_t __initcall_##fn##id __used

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

    173

    ---------------------------------------------------------------------

    __define_initcall()宏只是定义一个initcall_t类型的静态变量,并且声明要把这个静态变量放在特定的段里而已。上面我们看到initcall_t即是指向一个无参数有int返回值的函数的指针。

    许多的子系统都有自己的初始化函数,而这些初始化的函数又根据功能不同被分开在不同的子段里,子段的排列顺序则由链接决定。为了向后兼容,initcall()把调用,也就是一个个指向初始化函数的函数指针放进设备初始化子段里。

    在各个平台的链接脚本文件arch/xxx/kernel/vmlinux.lds.S中,我们总能看到下面的语句:

    INIT_CALLS

    这个宏有如下的定义:

    ---------------------------------------------------------------------

    include/asm-generic/vmlinux.lds.h

    606 #define INIT_CALLS                                           

    607                 VMLINUX_SYMBOL(__initcall_start) = .;        

    608                 INITCALLS                                    

    609                 VMLINUX_SYMBOL(__initcall_end) = .;

    ---------------------------------------------------------------------

    INIT_CALLS即是定义一个新的段,而定义段的字段的任务则由宏INITCALLS完成:

    ---------------------------------------------------------------------

    include/asm-generic/vmlinux.lds.h

    585 #define INITCALLS                                            

    586         *(.initcallearly.init)                               

    587         VMLINUX_SYMBOL(__early_initcall_end) = .;            

    588         *(.initcall0.init)                                   

    589         *(.initcall0s.init)                                  

    590         *(.initcall1.init)                                   

    591         *(.initcall1s.init)                                  

    592         *(.initcall2.init)                                   

    593         *(.initcall2s.init)                                  

    594         *(.initcall3.init)                                   

    595         *(.initcall3s.init)                                  

    596         *(.initcall4.init)                                   

    597         *(.initcall4s.init)                                  

    598         *(.initcall5.init)                                   

    599         *(.initcall5s.init)                                  

    600         *(.initcallrootfs.init)                              

    601         *(.initcall6.init)                                   

    602         *(.initcall6s.init)                                  

    603         *(.initcall7.init)                                   

    604         *(.initcall7s.init)

    ---------------------------------------------------------------------

    而这些初始化函数又是在何时调用的呢?我们看到start_kernel()-> rest_init()-> kernel_init()-> do_basic_setup(void)-> do_initcalls(),而正是do_initcalls()处理了这些初始化函数,其定义为:

    ---------------------------------------------------------------------

    init/main.c

    765 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

    766

    767 static void __init do_initcalls(void)

    768 {

    769         initcall_t *fn;

    770

    771         for (fn = __early_initcall_end; fn < __initcall_end; fn++)

    772                 do_one_initcall(*fn);

    773

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

    775         flush_scheduled_work();

    776 }

    ---------------------------------------------------------------------

    do_initcalls()又调用do_one_initcall()函数类处理这些调用。

    ---------------------------------------------------------------------

    init/main.c

    715 static char msgbuf[64];

    716 static struct boot_trace_call call;

    717 static struct boot_trace_ret ret;

    718

    719 int do_one_initcall(initcall_t fn)

    720 {

    721      int count = preempt_count();

    722      ktime_t calltime, delta, rettime;

    723

    724      if (initcall_debug) {

    725         call.caller = task_pid_nr(current);

    726         printk("calling  %pF @ %i ", fn, call.caller);

    727         calltime = ktime_get();

    728         trace_boot_call(&call, fn);

    729         enable_boot_trace();

    730     }

    731

    732     ret.result = fn();

    733

    734     if (initcall_debug) {

    735        disable_boot_trace();

    736        rettime = ktime_get();

    737        delta = ktime_sub(rettime, calltime);

    738        ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10;

    739        trace_boot_ret(&ret, fn);

    740        printk("initcall %pF returned %d after %Ld usecs ", fn,

    741        ret.result, ret.duration);

    742     }

    743

    744     msgbuf[0] = 0;

    745

    746     if (ret.result && ret.result != -ENODEV && initcall_debug)

    747        sprintf(msgbuf, "error code %d ", ret.result);

    748

    749     if (preempt_count() != count) {

    750        strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));

    751        preempt_count() = count;

    752     }

    753     if (irqs_disabled()) {

    754        strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));

    755        local_irq_enable();

    756     }

    757     if (msgbuf[0]) {

    758        printk("initcall %pF returned with %s ", fn, msgbuf);

    759     }

    760

    761     return ret.result;

    762 }

    ---------------------------------------------------------------------

  • 相关阅读:
    http请求
    git常用命令总结
    tomcat与iis公用80端口(已经发布.net项目现在开发Java项目时tomcat在eclipse中localhost:8080打不开问题)
    使用EasyUI的Datagrid的Editor进行行编辑,Enter回车结束编辑,并开启新的一行。
    js生成tree形组织机构下拉框
    ajaxFileUpload上传带参数,返回值改成json格式
    企业微信自建应用移动端动态获取li并给其事件问题总结
    easyui_validatebox常用验证
    常见的hash算法。。
    自己改编的布隆选择器。。
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5388137.html
Copyright © 2020-2023  润新知