linux内核中的subsys_initcall是干什么的?
注意:使用的内核源码版本为5.1.3
1. subsys_initcall长什么样子?
它其实是个宏定义,定义如下:
#define subsys_initcall(fn) __define_initcall(fn, 4) (注意,这是使用在内置模块中的)
或
#define subsys_initcall(fn) module_init(fn) (注意,这是使用在可加载模块中的)
2. 进一步解剖__define_initcall
#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
3. 再解剖___define_initcall
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
#define ___define_initcall(fn, id, __sec) \
__ADDRESSABLE(fn) \
asm(".section \"" #__sec ".init\", \"a\" \n" \
"__initcall_" #fn #id ": \n" \
".long " #fn " - . \n" \
".previous \n");
#else
#define ___define_initcall(fn, id, __sec) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(#__sec ".init"))) = fn;
#endif
4. 结合以上内容可知
如果未定义宏CONFIG_HAVE_ARCH_PREL32_RELOCATIONS,那么subsys_initcall就被展开为:
static initcall_t __initcall_fn4 __used \
__attribute__((__section_(.initcall4.init))) = fn
也就是将fn链接到段.initcall4.init中
5. subsys_initcall与module_init有何联系?
5.1 先看看module_init是什么吧?
/* Each module must use one module_init(). */ (在编译为可加载模块时使用这个定义)
#define module_init(initfn) \
static inline initcall_t __maybe_unused __inittest(void) \
{ return initfn; } \
int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
或
define module_init(x) __initcall(x); (在编译为内置模块时使用这个定义)
5.2 __initcall的定义是怎样的呢?
#define __initcall(fn) device_initcall(fn)
5.3 device_initcall是怎样的呢?
#define device_initcall(fn) __define_initcall(fn, 6)
5.4 结论
从以上分析可以看出:
在编译某驱动为内置代码时,subsys_initcall与module_init仅仅是__define_initcall的第二个参数不同而已,前者使用4,后者使用6,因此归纳出仅仅是谁先被执行的差异,subsys_initcall比module_init先执行
最新文章
- MyBatis5:MyBatis集成Spring事物管理(上篇)
- 【转载】 删除Win10“这台电脑”中的6个文件夹
- mysql 与 mycat集成读写分离
- OC冒泡排序
- java 自带md5加密
- Redis PHP通用类
- Strom的安装及使用
- C# 如何使用配置文件保存应用程序里的配置数据
- firstPage
- Spring中新建记录后返回自增主键的处理方法
- phpmailer使用qq邮箱、163邮箱成功发送邮件实例代码
- elasticsearch 5.1 别的机器无法访问9200端口
- JSR303 分組数据验证的使用
- 转:WCAT 压力工具介绍
- Hbuilder配置识别逍遥安卓模拟器
- jquery 取子节点及当前节点属性值
- git分支名一直带rebasing,如何去除
- catkin-tools
- Clever Little Box 电缆组件 USB A 插座 至 USB B 插头
- 高中生的IT之路-1.5西餐厅服务生