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相关推荐

  1. Linux内核跟踪之trace框架分析【转】

    转自:http://blog.chinaunix.net/uid-20543183-id-1930846.html ------------------------------------------ ...

  2. linux内核网络协议栈--监控和调优:接收数据(十五)

    译者序 本文翻译自 2016 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Receiving Data.如果能看懂英文,建议阅 ...

  3. 神秘的subsys_initcall【转】

    转自:http://blog.chinaunix.net/uid-12567959-id-161015.html 在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢? ...

  4. (笔记)Linux内核学习(五)之中断推后处理机制

    一 中断 硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断. 硬件中断优先级很高,打断当前正在执行的程序.有两种情况: 硬件中断在中断处理程序中处理 硬件中断延 ...

  5. Linux数据报文接收发送总结4

    二.系统初始化 Linux驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行.比如要提前创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网络设备子系统要提前初始 ...

  6. 性能优化:如何更快地接收数据

    从网卡到应用程序,数据包会经过一系列组件,其中驱动做了什么?内核做了什么?为了优化,我们又能做些什么?整个过程中涉及到诸多细微可调的软硬件参数,并且相互影响,不存在一劳永逸的"银弹" ...

  7. linux进程管理之mm_struct,【转】Linux进程管理之SMP负载平衡(续二)

    继续来分析balance_tasks()函数,结合代码中的注释,理解这段代码应该很容易,在这里主要分析它的两个重要的子函数,即can_migrate_task()和pull_task(). 先来看ca ...

  8. Linux内核学习笔记五——中断推后处理机制

    一 中断 硬件通过中断与操作系统进行通信,通过对硬件驱动程序处注册中断处理程序,快速响应硬件的中断. 硬件中断优先级很高,打断当前正在执行的程序.有两种情况: 硬件中断在中断处理程序中处理 硬件中断延 ...

  9. Linux内核 eBPF基础:perf(1):perf_event在内核中的初始化

    Linux内核 eBPF基础 perf(1):perf_event在内核中的初始化 荣涛 2021年5月12日 本文相关注释代码:https://github.com/Rtoax/linux-5.10 ...

最新文章

  1. 16 分频 32 分频是啥意思_Verilog中任意分频的实现
  2. 监控io性能, free命令, ps命令, 查看网络状态, linux下抓包
  3. Smartforms Debug
  4. Android studio 如何查看模拟器里面的文件
  5. lintcode:二叉树的层次遍历
  6. 在多种浏览器中嵌入Applet
  7. 今天看明白了,为什么有些属性会这样写了:public string status{get;set;}
  8. CVPR 2019全部论文下载!
  9. oracle主备不同步,主备环境下数据不一致重新部署复制
  10. Airflow集成在线编写创建dag的插件
  11. 多线程并发思考--文件加锁
  12. html隐藏地址栏,js新打开页面隐藏地址栏
  13. Knowledge Distillation论文阅读之:综述文章:Knowledge Distillation: A Survey(未完待续····)
  14. Unity 实现批量Build打包
  15. 使用css3实现一个超浪漫的新年倒计时
  16. 抖音短视频标题什么样的容易火:国仁楠哥
  17. vscode的c_cpp_properties.json
  18. 小笑话一则,但是却引人深思,谁能讲出它更深成的意义
  19. 宗镜录略讲——南怀瑾老师——系列11
  20. 网页设计师常去的综合类网站总结-卢松松博客

热门文章

  1. 绕过云盾找真实IP-找真实IP-绕过CDN
  2. 无理数,用于图案自动生成
  3. 四旋翼无人机建模与实现(三)
  4. 服务器时间相差八小时问题解决
  5. Windows下PHP开发工具WAMP
  6. 线性代数 --- 线性方程组的相容与不相容(个人笔记扫描版)
  7. R语言随笔-COG计算及绘图
  8. 根据身份证号码判断性别 java
  9. 服务器系统安全【10大注意事项】
  10. 如何用标签打印软件制作物料标识卡