转自: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. classpath与clsspath*

    classpath是指 WEB-INF文件夹下的classes目录 classes含义: 1.存放各种资源配置文件 eg.init.properties log4j.properties struts ...

  2. 重温jsp③

    Jsp详细   九大内置对象 Out jsp的输出流,用来向客户端响应 page 当前jsp对象!他的引用类型是object,即真身中有如下代码:object page=this: Session h ...

  3. 腾讯云申请的64位ubuntu服务器配置php环境

    腾讯云申请的64位ubuntu服务器配置php环境 一.首先还是安装Lamp组合 Linux+Apache+Mysql+php 直接命令 sudo apt-get install apache2 su ...

  4. 自定义SQL语句

    在用@query写了sql语句后,返回的结果集不能自动转换为自定义的对象. 百度有一篇博客,解决方案是直接在sql语句里实例化对象,我用了,但是语法错误,又谷歌了下,sql语句里是不能这样写的,这是h ...

  5. JS基础(四)运算符

    一.比较运算符 1.== : 判断两边值是否相等 2.>= : 判断左边的值是否大于或等于右边的值 3.<= : 判断左边边的值是否小于或等于右边的值 4.>   : 判断左边的值是 ...

  6. Linux命令(二十四) 磁盘管理命令(二) mkfs,mount

    一.格式化文件系统 mkfs 当完成硬盘分区以后要进行硬盘的格式化,mkfs系列对应的命令用于将硬盘格式化为指定格式的文件系统.mkfs 本身并不执行建立文件系统的工作,而是去调用相关的程序来执行.例 ...

  7. [国家集训队]middle

    [国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...

  8. 【笔记】自学ST表笔记

    自学ST表笔记 说实话原先QBXT学的ST表忘的差不多了吧...... 我重新自学巩固一下(回忆一下) 顺便把原先一些思想来源的原博发上来 一.ST表简介 ST表,建表时间\(O(n\cdot log ...

  9. Mybatis返回HashMap时,某个字段值为null时,不会保存key

    转载: http://blog.csdn.net/little2z/article/details/38525327 mybatis 的 callSettersOnNulls 问题项目用到mybati ...

  10. 【刷题】BZOJ 2095 [Poi2010]Bridges

    Description YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛.现在YYD想骑单车从小岛1 ...