module_init与module_exit

本文介绍了一个简单的Linux驱动程序示例,包括源代码及Makefile配置。该驱动程序通过 printk 函数输出欢迎和退出信息,并提供了加载和卸载驱动的方法。

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

这是一个简单的linux驱动程序:

/*包含声明开源与作者的两个函数*/
#include <linux/module.h>
/*包含入口与出口函数*/
#include <linux/init.h>

//声明开源,声明作者可有可无
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("kingyal");

static int hello_init(void);
static void hello_exit(void);

static int hello_init(void)
{
    /*打印信息,KERN_EMERG表示紧急信息*/
    printk(KERN_EMERG "welcome to linux world!\n");
    return 0;
}

static void hello_exit(void)
{
        /*打印信息,KERN_EMERG表示紧急信息*/
    printk(KERN_EMERG "exit linux world!\n");
}

/*入口与出口函数*/
module_init(hello_init);
module_exit(hello_exit);

如下是makefile文件:

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += drivermodule.o

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
    make -C $(KDIR) M=$(PWD) modules
        
#make clean执行的操作是删除后缀为o的文件
clean:
    rm -rf *.o

运行makefile文件,生成drivermodule.ko文件,这里用动态加载文件到内核的方法,再iTop4412上加载insmod drivermodule.ko文件,移除驱动可用rmmod drivermodule.ko,结果如下图所示:

### 后期初始化函数 `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、付费专栏及课程。

余额充值