early_initcall
early_initcall
- 1. 定义
- 1.1 模块加载
- 1.1.1 module_init
- 1.1.2 module_exit
- 1.2 直接加载
- 2. 总结
1. 定义
分为模块加载与直接加载。定义位置如下:
~/code/linux-6.1/kernel/stop_machine.c [FORMAT=unix] [TYPE=C] [POS=584,1][82%] 15/12/22 - 16:09
Cscope tag: early_initcall# 行 文件名 / 上下文 / 行1 269 include/linux/init.h <<early_initcall>>#define early_initcall(fn) __define_initcall(fn, early)2 110 include/linux/module.h <<early_initcall>>#define early_initcall(fn) module_init(fn)
1.1 模块加载
定义位置:include/linux/module.h
#define early_initcall(fn) module_init(fn)
#define core_initcall(fn) module_init(fn)
#define core_initcall_sync(fn) module_init(fn)
#define postcore_initcall(fn) module_init(fn)
#define postcore_initcall_sync(fn) module_init(fn)
#define arch_initcall(fn) module_init(fn)
#define subsys_initcall(fn) module_init(fn)
#define subsys_initcall_sync(fn) module_init(fn)
#define fs_initcall(fn) module_init(fn)
#define fs_initcall_sync(fn) module_init(fn)
#define rootfs_initcall(fn) module_init(fn)
#define device_initcall(fn) module_init(fn)
#define device_initcall_sync(fn) module_init(fn)
#define late_initcall(fn) module_init(fn)
#define late_initcall_sync(fn) module_init(fn)#define console_initcall(fn) module_init(fn)
在模块加载时,所有的*_initcall
都调用module_init
函数,不管调用上述的哪个函数,都是相同的,没有加载优先级一说。如果需要控制加载的顺序,需要调整insmod *.ko
命令的顺序。
1.1.1 module_init
看一下module_init是如何实现的。
定义如下
#ifndef MODULE
#define module_init(x) __initcall(x);
#else /* MODULE */
/* 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))); \___ADDRESSABLE(init_module, __initdata);
#endif
1) 首先,前两行内容是用于初始化自测的,这里不进行展开;
2) 其次,重要的两行为设置initfn
的别名为init_module
。
int init_module(void) __copy(initfn) \__attribute__((alias(#initfn))); \
- alias的gcc编译器的语法如下:
链接: alias gcc定义
从gcc的编译器语法,就可以理解这两行内容的主要作用了。就是将传入的参数initfn
重命名为init_module
。那么为何要这么做呢?猜测是在insmod
命令的实现中,会直接调用init_module
函数,待后续查证。
注:#
号的作用为,将后续的代码进行字符化。根据gcc编译器语法,接收的参数为"__f"
为字符串变量,因此需要添加#将传入的initfn
字符化。
3) 最后,告知编译器,强制将init_module定义为symbol。
1.1.2 module_exit
module_exit与module_init类似,不做过多介绍。
#define module_exit(exitfn) \static inline exitcall_t __maybe_unused __exittest(void) \{ return exitfn; } \void cleanup_module(void) __copy(exitfn) \__attribute__((alias(#exitfn))); \___ADDRESSABLE(cleanup_module, __exitdata);
1.2 直接加载
定义位置:include/linux/init.h
#define early_initcall(fn) __define_initcall(fn, early)/** A "pure" initcall has no dependencies on anything else, and purely* initializes variables that couldn't be statically initialized.** This only exists for built-in code, not for modules.* Keep main.c:initcall_level_names[] in sync.*/
#define pure_initcall(fn) __define_initcall(fn, 0)#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)#define __initcall(fn) device_initcall(fn)#define __exitcall(fn) \static exitcall_t __exitcall_##fn __exit_call = fn#define console_initcall(fn) ___define_initcall(fn, con, .con_initcall)
通过定义可以看到该系列函数,都调用的为__define_initcall
函数,不同点为第二个参数,第二个参数的不同决定了相应函数的调用顺序。
2. 总结
1) *_initcall
系列函数分为两种实现方式,一种为直接加载,一种为模块加载。
2) 直接加载:根据调用函数不同,初始化的顺序不同。
3) 模块加载:实现相同,初始化顺序由insmod命令顺序决定。
early_initcall相关推荐
- Linux内核跟踪之trace框架分析【转】
转自:http://blog.chinaunix.net/uid-20543183-id-1930846.html ------------------------------------------ ...
- linux内核网络协议栈--监控和调优:接收数据(十五)
译者序 本文翻译自 2016 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Receiving Data.如果能看懂英文,建议阅 ...
- 神秘的subsys_initcall【转】
转自:http://blog.chinaunix.net/uid-12567959-id-161015.html 在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢? ...
- (笔记)Linux内核学习(五)之中断推后处理机制
一 中断 硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断. 硬件中断优先级很高,打断当前正在执行的程序.有两种情况: 硬件中断在中断处理程序中处理 硬件中断延 ...
- Linux数据报文接收发送总结4
二.系统初始化 Linux驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行.比如要提前创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网络设备子系统要提前初始 ...
- 性能优化:如何更快地接收数据
从网卡到应用程序,数据包会经过一系列组件,其中驱动做了什么?内核做了什么?为了优化,我们又能做些什么?整个过程中涉及到诸多细微可调的软硬件参数,并且相互影响,不存在一劳永逸的"银弹" ...
- linux进程管理之mm_struct,【转】Linux进程管理之SMP负载平衡(续二)
继续来分析balance_tasks()函数,结合代码中的注释,理解这段代码应该很容易,在这里主要分析它的两个重要的子函数,即can_migrate_task()和pull_task(). 先来看ca ...
- Linux内核学习笔记五——中断推后处理机制
一 中断 硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断. 硬件中断优先级很高,打断当前正在执行的程序.有两种情况: 硬件中断在中断处理程序中处理 硬件中断延 ...
- Linux内核 eBPF基础:perf(1):perf_event在内核中的初始化
Linux内核 eBPF基础 perf(1):perf_event在内核中的初始化 荣涛 2021年5月12日 本文相关注释代码:https://github.com/Rtoax/linux-5.10 ...
最新文章
- 16 分频 32 分频是啥意思_Verilog中任意分频的实现
- 监控io性能, free命令, ps命令, 查看网络状态, linux下抓包
- Smartforms Debug
- Android studio 如何查看模拟器里面的文件
- lintcode:二叉树的层次遍历
- 在多种浏览器中嵌入Applet
- 今天看明白了,为什么有些属性会这样写了:public string status{get;set;}
- CVPR 2019全部论文下载!
- oracle主备不同步,主备环境下数据不一致重新部署复制
- Airflow集成在线编写创建dag的插件
- 多线程并发思考--文件加锁
- html隐藏地址栏,js新打开页面隐藏地址栏
- Knowledge Distillation论文阅读之:综述文章:Knowledge Distillation: A Survey(未完待续····)
- Unity 实现批量Build打包
- 使用css3实现一个超浪漫的新年倒计时
- 抖音短视频标题什么样的容易火:国仁楠哥
- vscode的c_cpp_properties.json
- 小笑话一则,但是却引人深思,谁能讲出它更深成的意义
- 宗镜录略讲——南怀瑾老师——系列11
- 网页设计师常去的综合类网站总结-卢松松博客