文件操作结构体file_operations的完整定义见博文 http://iyenn.com/rec/1709536.html
嵌入式驱动编程中结构体file_operations的第一个成员 struct module *owner 通常被赋值为 THIS_MODULE 这是怎么回事儿?
比如下面的代码:
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
};
- 1
- 2
- 3
- 4
- 5
我们在Linux的源码中(include\linux\export.h
)可以查到THIS_MODULE
是一个宏定义,具体如下:
#ifdef MODULE
extern struct module __this_module;
#define THIS_MODULE (&__this_module)
#else
#define THIS_MODULE ((struct module *)0)
#endif
- 1
- 2
- 3
- 4
- 5
- 6
把这段代码理解了,基本上就理解了,下面是详细讲解。
在 Linux 内核中,THIS_MODULE
是一个宏,用于指向当前驱动模块的 struct module
实例。它的作用是为模块提供元信息和生命周期管理支持。
THIS_MODULE
的定义解读
#ifdef MODULE
extern struct module __this_module;
#define THIS_MODULE (&__this_module)
#else
#define THIS_MODULE ((struct module *)0)
#endif
- 1
- 2
- 3
- 4
- 5
- 6
-
MODULE
宏:MODULE
是一个条件编译宏,当编译成模块(.ko
文件)时,编译器会定义MODULE
。- 如果模块被静态编译进内核(而不是动态加载的模块),
MODULE
不会被定义。
-
__this_module
:- 如果
MODULE
被定义,THIS_MODULE
会展开为&__this_module
,即当前模块的struct module
实例。 __this_module
是一个由内核自动生成的全局变量,包含模块的相关信息,如模块名、引用计数等。
- 如果
-
静态内核情况:
- 如果模块被静态编译进内核,
MODULE
未定义,此时THIS_MODULE
被设置为NULL
,因为静态内核中的模块不需要动态管理。
- 如果模块被静态编译进内核,
THIS_MODULE
在驱动中的用途
THIS_MODULE
被赋值给 struct file_operations
的 owner
成员,主要用于模块的引用计数管理:
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
-
模块引用计数:
- 当设备文件被打开时(调用
open
函数),内核会增加模块的引用计数,防止模块在使用过程中被卸载。 - 当设备文件被关闭时(调用
release
函数),内核会减少引用计数。
- 当设备文件被打开时(调用
-
避免非法卸载:
- 如果模块的引用计数大于 0,
rmmod
命令无法卸载该模块,从而防止非法卸载可能导致的系统崩溃。
- 如果模块的引用计数大于 0,
-
动态模块管理:
- 通过
THIS_MODULE
,内核可以准确管理模块的生命周期,包括加载、使用和卸载。
- 通过
struct module
的结构
struct module
定义在
中,主要包含以下信息:
struct module {
const char *name; // 模块名称
struct list_head list; // 模块链表
struct module_kobject mkobj; // 模块的 kobject
struct module_param_attrs *param_attrs; // 模块参数的 sysfs 接口
struct list_head source_list; // 源文件相关信息
unsigned int taints; // 模块的 taints 标志
struct mutex mutex; // 模块互斥锁
unsigned long state; // 模块的状态
...
unsigned int refcnt; // 引用计数
...
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
name
: 模块名称。refcnt
: 引用计数,记录模块被使用的次数。state
: 模块状态,例如正在初始化、已加载等。
在动态加载和静态内核中的差异
-
动态加载模块:
- 使用
THIS_MODULE
,owner
会指向&__this_module
,从而实现引用计数管理。
- 使用
-
静态编译进内核:
THIS_MODULE
为NULL
,因为静态模块不会被卸载,也不需要引用计数管理。
一个示例:模块的引用计数管理
假设一个设备驱动模块如下:
#include
#include
#include
static int dev_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device opened\n");
return 0;
}
static int dev_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "Device released\n");
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = dev_open,
.release = dev_release,
};
static int __init mod_init(void) {
int major = register_chrdev(0, "my_device", &fops);
printk(KERN_INFO "Module loaded, major number %d\n", major);
return 0;
}
static void __exit mod_exit(void) {
unregister_chrdev(0, "my_device");
printk(KERN_INFO "Module unloaded\n");
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_LICENSE("GPL");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
-
当设备文件
/dev/my_device
被打开时:- 内核通过
THIS_MODULE
增加引用计数,防止模块被卸载。 - 调用
dev_open
函数。
- 内核通过
-
当设备文件被关闭时:
- 内核通过
THIS_MODULE
减少引用计数。 - 调用
dev_release
函数。
- 内核通过
总结
THIS_MODULE
是一个宏,用于引用当前模块的 struct module
实例【注意:当前模块的 struct module
的实例是由系统自动生成的】,主要作用是管理模块的引用计数,防止模块在使用过程中被非法卸载。它的工作机制依赖于内核的模块管理框架,与设备驱动的生命周期紧密相关。
由于我们编写的驱动程序本质上也是一个模块,所以我们需要用到宏THIS_MODULE
。

昊虹嵌入式技术交流群
QQ群名片


评论记录:
回复评论: