Kernel启动时 驱动是如何加载的module_init,加载的次序如何;略见本文

Linux内核在启动过程中,驱动模块的加载顺序由initcall宏定义决定,如纯初始化、核心初始化等不同阶段。module_init对应的启动序号为6,在do_initcalls函数中执行。驱动的具体启动顺序在同一优先级下由Makefile中的.o文件链接次序决定。可通过system.map查看详细次序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Init.h中有相关initcall的启动次序,在system.map中可看出具体的__initcall指针的前后次序

 

#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)

### 后期初始化函数 `later_init` 和模块初始化函数 `module_init` 在 Linux 内核开发中,`later_init` 并不是一个标准的术语或宏定义,但它可能指的是某些特定场景下的后期初始化逻辑。而 `module_init` 是一个广泛使用的宏,用于指定模块加载时执行的入口函数。 #### 1. **`module_init` 宏** `module_init` 是一种机制,允许开发者为内核模块指定一个初始化函数,在模块被加载到内核时自动调用该函数。其核心实现依赖于 GCC 的属性扩展功能 (`__attribute__((constructor))`) 或类似的链接器脚本技术[^4]。 以下是 `module_init` 的基本工作原理: - 当编译带有 `module_init(init_function)` 的代码时,`init_function` 被标记为需要优先运行的函数之一。 - 在模块加载过程中,内核会扫描这些特殊标记的函数并依次调用它们。 示例代码如下: ```c #include <linux/module.h> #include <linux/kernel.h> static int __init my_module_init(void) { printk(KERN_INFO "Module initialized\n"); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "Module exited\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); ``` 上述代码中的 `my_module_init` 函数会在模块加载时被执行。 --- #### 2. **假设的 `later_init` 场景** 虽然没有官方文档提及名为 `later_init` 的具体概念,但在实际项目中可能存在类似的功能需求。例如,有些驱动程序或子系统希望延迟部分初始化操作直到更晚的时间点完成(比如等待其他组件准备好)。这种情况下可以手动设计类似于 `later_init` 的机制。 常见的做法包括但不限于以下几种方式: - 使用定时器接口(如 `timer_setup()`),安排某个延后的回调函数; - 利用工作队列(workqueue)提交异步任务; - 借助设备模型框架的通知链表监听事件触发条件满足后再继续处理剩余步骤; 下面是一个简单的例子展示如何通过 workqueue 实现所谓的 “late init” 功能: ```c #include <linux/workqueue.h> #include <linux/init.h> #include <linux/module.h> struct delayed_work my_late_init_work; void late_init_handler(struct work_struct *work) { pr_info("Late initialization completed.\n"); } DECLARE_DELAYED_WORK(my_late_init_work, late_init_handler); static int __init early_init(void){ queue_delayed_work(system_wq,&my_late_init_work,msecs_to_jiffies(500)); pr_info("Early initialization done, scheduling late init...\n"); return 0; } static void __exit cleanup_mod(void){ cancel_delayed_work_sync(&my_late_init_work); pr_info("Cleanup complete.\n"); } module_init(early_init); module_exit(cleanup_mod); MODULE_LICENSE("Dual BSD/GPL"); ``` 在这个案例里,“早起”的初始化由 `early_init` 执行完毕后立即调度了一个延迟作业去稍候再做额外的工作——即所谓“晚期”。 --- #### 3. **两者的对比** | 特性 | `module_init` | 自定义 `later_init` | |--------------------------|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| | 初始化时机 | 模块载入瞬间 | 可设定任意时间间隔 | | 是否内置支持 | 是 | 需要自行构建 | | 应用范围 | 主要用作模块启动阶段的核心配置 | 更适合那些需分多阶段逐步完善的复杂对象 | 需要注意的是,如果确实存在某种形式的标准 API 名叫 `later_init`,那么它应该属于某特定领域或者第三方补丁集的一部分而不是原生Linux Kernel所提供. --- ### 结论 综上所述,尽管两者都涉及到了系统的初始化过程,但是他们针对的应用场合以及具体的运作模式存在着明显的差异。对于常规意义上的插件化管理来说推荐采用成熟的 `module_init`;而对于更加精细控制的需求则考虑引入自定义方案诸如基于WorkQueue等手段达成目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值