转自:http://www.cnblogs.com/superlcc/archive/2012/09/12/2681930.html

现在以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的执行时刻了吧。

各种initcall的执行先后顺序(module_init、postcore_initcall、arch_initcall、subsys_initcall、 fs_initcall)【转】的更多相关文章

  1. Java中的继承与静态static等的执行先后顺序

    package extend; public class X { Y y=new Y(); static{  System.out.println("tttt"); } X(){  ...

  2. Oracle执行计划顺序

    先从最开头一直往右看,直到看到最右边的并列的地方,对于不并列的,靠右的先执行:对于并列的,靠上的先执行.      即并列的缩进块,从上往下执行,非并列的缩进块,从下往上执行. 如下示例: Execu ...

  3. Spring切面通知执行的顺序(Advice Order)

    问题描述 如果在Spring的程序中同时定义了环绕通知(Around)和前置通知(Before)..那么,有以下问题: 1.怎么让两个切面通知都起作用 2.或者让两者切面按自己指定的顺序进行执行? 3 ...

  4. spring通知执行的顺序

    点击下载本示例相关代码 关于spring aop的具体使用,暂时不在这里讲解,后面会特定来讲解,本次主要探讨spring中通知执行的顺序. spring中通知分为以下几种: before:前置通知,在 ...

  5. throw和throws的区别以及try,catch,finally在有return的情况下执行的顺序

    一,抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常.下面它们之间的异同. (1).系统自动抛异常 1.当程序语句出现一些逻辑错误.主义错误或类型转换错误时,系统会自动抛出 ...

  6. mysql 中语句执行的顺序以及查询处理阶段的分析

    原文链接:http://www.php.cn/mysql-tutorials-408865.html 本篇文章给大家带来的内容是关于mysql中语句执行的顺序以及查询处理阶段的分析,有一定的参考价值, ...

  7. spring多个AOP执行先后顺序(面试问题:怎么控制多个aop的执行循序)

    转载:spring多个AOP执行先后顺序(面试问题:怎么控制多个aop的执行循序) 众所周知,spring声明式事务是基于AOP实现的,那么,如果我们在同一个方法自定义多个AOP,我们如何指定他们的执 ...

  8. JavaScript执行优先顺序

    js在html中的加载执行顺序 1.加载顺序:引入标记<script />的出现顺序, 页面上的Javascript代码是HTML文档的一部分,所以Javascript在页面装载时执行的顺 ...

  9. Python+selenium之unittest单元测试(3)关于测试用例执行的顺序

    一.测试用例执行的顺序 用例的执行顺序涉及多个层级,在多个测试目录的情况下,先执行哪个目录?在多个测试文件的情况下,先执行哪个文件?在多个测试类的情况下,先执行哪个测试类?,在多个测试方法(用例)的情 ...

随机推荐

  1. 05 方法与数组笔记【JAVA】

    ---恢复内容开始--- 1:方法(掌握) (1)方法:就是完成特定功能的代码块. 注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法. (2)格式: 修饰符 返回值类型 方法名(参数类 ...

  2. beta NO1

    031602111 傅海涛 1.今天进展 笔记颜色统一,解决笔记的同步性和完整性 2.存在问题 office文档转换的时间问题 3.明天安排 增加新功能和完善之前的功能 4.心得体会 接口真难 031 ...

  3. sql 索引 sql_safe_updates

    为了数据的安全性,mysql有一个安全性设置,sql_safe_updates ,当把这个值设置成1的时候,当程序要对数据进行修改删除操作的时候条件必须要走索引. 刚好现在也碰到了此类问题:网上找了相 ...

  4. ThreadLocal变量

    什么是ThreadLocal变量?ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多.可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副 ...

  5. delphi 如何让ScrollBox的内容与滚动条一起实时滚动

    delphi 如何让ScrollBox的内容与滚动条一起实时滚动 拖动滚动条后只有释放鼠标键,ScrollBox的内容才会滚动到实际位置,不爽.请问高人,怎样才能使拖动ScrollBox的滚动条的同时 ...

  6. Hbase之JavaAPI连接池

    源码: package HbaseOperation; import com.alibaba.fastjson.JSON; import org.apache.hadoop.conf.Configur ...

  7. NESTED内部事务异常会回滚 外部事务不会回滚 ;内部事务没有异常,外部事务有异常 则整体事务都回滚

    NESTED内部事务异常会回滚 外部事务不会回滚 :内部事务没有异常,外部事务有异常 则整体事务都回滚

  8. java数组倒序查找值

    java语言里面没有arr[:-2]这种方式取值 只能通过  arr[arr.length-1-x]的方式取值倒数的 x(标示具体的某个值)

  9. 别在int与float上栽跟头

    int与float是我们每天编程都用的两种类型,但是我们真的足够了解它们吗.昨天在博客园看到一个比较老的笑话: “昨天晚上下班回家,一民警迎面巡逻而来.突然对我大喊:站住!民警:int 类型占几个字节 ...

  10. Pathwalks CodeForces - 960F(主席树 || 树状数组)

    题意: 求树上最长上升路径 解析: 树状数组版: 998ms edge[u][w] 代表以u为一条路的终点的小于w的最长路径的路的条数 · 那么edge[v][w] = max(edge[u][w-1 ...