以下详细介绍一下 do_initcall()
、late_initcall
以及 do_initcall(late_initcall)
的执行机制,并对比它们的异同。同时也会拓展介绍其他类型的 initcall 函数。
-
do_initcall()
- 这是内核用于执行所有 initcall 函数的核心函数
- 它会遍历所有已注册的 initcall level,依次执行每个 level 中的初始化函数
- 内部实现如下:
static void __init do_initcalls(void) { int level; for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) do_initcall_level(level); }
-
late_initcall
late_initcall
是一种特殊的 initcall 类型- 它会在所有其他 initcall 函数都执行完之后才被调用
late_initcall
定义的函数会被放在.initcall7.init
这个内核段中- 这主要用于一些依赖其他模块或需要最后初始化的功能
-
do_initcall(late_initcall)
- 这是一种特殊的使用方式,会将
late_initcall
函数作为一种普通的 initcall 来执行 - 与直接使用
late_initcall
不同,这种方式可以让late_initcall
函数在其他 initcall 之前执行 - 内部实现上,
do_initcall(late_initcall)
会将函数放在.initcall6.init
段,而不是.initcall7.init
- 这是一种特殊的使用方式,会将
对比:
do_initcall()
是核心的 initcall 执行函数,遍历所有已注册的 initcall levellate_initcall
是一种特殊的 initcall,在所有其他 initcall 执行完后才会被调用do_initcall(late_initcall)
是一种特殊用法,可以让late_initcall
函数提前执行
其他主要的 initcall 函数还有:
early_initcall
- 最早执行的初始化函数,用于硬件和基础功能初始化core_initcall
- 核心模块初始化,分为3个级别(core, sync, postcore)subsys_initcall
- 子系统初始化fs_initcall
- 文件系统初始化device_initcall
- 设备驱动初始化,分6个级别
这些 initcall 函数都有严格的执行顺序,确保内核初始化有序进行,依赖关系得到满足。
总的来说,do_initcall()
是内核初始化的核心入口,负责遍历执行所有已注册的 initcall 函数。late_initcall
则是一种特殊的 initcall,在其他函数都执行完后才会被调用。而 do_initcall(late_initcall)
则是一种特殊用法,可以让 late_initcall
函数在其他 initcall 之前执行。