Android
的
module_init
和
module_exit
的定义在
common/include/linux/Init.h
module_init
和
module_exit
在
MODULE
宏有没有定义的情况下展开的内容是不同的。
如果
MODULE
这个宏没有定义,基本上表明该模块是要编译进内核的(obj-y)。
一、在MODULE没有定义时
在
MODULE
没有定义这种情况下,
module_init
和
module_exit
定义如下:
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.
*/
#define
module_init(x)
__initcall(x);
/**
* module_exit() - driver exit entry point
* @x: function to be run when driver is removed
*
* module_exit() will wrap the driver clean-up code
* with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically
* compiled into the kernel, module_exit() has no effect.
* There can only be one per module.
*/
#define
module_exit(x)
__exitcall(x);
...........................................................
#define
__initcall(fn)
device_initcall(fn)
#define
__exitcall(fn)
\
static exitcall_t __exitcall_##fn __exit_call = fn
这里
module_init(x)
被直接定义成了
__initcall(x)
。而
__initcall(x)
中又被定义成了
device_initcall(fn)
。
device_initcall(fn)的
fb函数将在Linux系统启动过程中(
start_kernel()
->
rest_init()
->
kernel_init()
->
do_basic_setup()
->
do_initcalls()
中)被调用,因此
module_init(x)也是在Linux系统启动过程中被调用。
如果
MODULE
这个宏没有定义,基本上表明该模块是要编译进内核的(obj-y)。所以我觉得
module_exit(x)
此时应该最终会被忽略掉,因为编译进入内核的模块是不需要进行清理工作的。
二、在MODULE被定义时
.在MODULE被定义的情况下(大部分可动态加载的driver模块都属于此, obj-m),module_init和module_exit定义如下:
/* Each module must use one module_init(). */
#define
module_init
(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((
alias
(#initfn)));
/* This is only required if you want to be unloadable. */
#define
module_exit
(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((
alias
(#exitfn)));
这段宏定义关键点是后面一句,通过
alias
将initfn变名为
init_module
。前面那个__inittest的定义其实是种技巧,用来对initfn进行某种静态的类型检查,如果阁下将模块初始化函数定义成,比如,void gpio_init(void)或者是int gpio_init(int),那么在编译时都会有类似下面的warning:
GPIO/fsl-gpio.c: In function '__inittest':
GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type
通过module_init将模块初始化函数统一别名为
init_module
,这样以后在载入模块的时候,在系统内部会调用sys_init_module()去找到init_module函数的入口地址。
如果
objdump -t gpio.ko
,就会发现
init_module
和
gpio_init
位于相同的地址偏移处。简言之,这种情况下模块的初始化函数在模块被载入的时候被调用。
module_exit
和
init_module
同理
,
只是
module_exit
是在模块被卸载的时候调用。