android——module_init内核调用顺序

    最近有在做一个初始化设备的动作,但是发现在相同的文件夹下已经有两个module_init,当我想再添加一个时,发现我添加的这个是最后执行的。由于其他的两个初始化中有用到我添加的部分,所以想提高优先级。没办法,只能看下module_init在initcall的优先级,然后选取一个合适的。

一、同一个文件中的三个module_init

    1、我想要添加的部分

static int __init mdss_dsi_bl_driver_init(void)
{
	int ret;

	ret = mdss_dsi_bl_register_driver();
	if (ret) {
		pr_err("mdss_dsi_bl_register_driver() failed!\n");
		return ret;
	}

	return ret;
}
module_init(mdss_dsi_bl_driver_init);

    2、原始文件中已经存在的部分

module_init(mdss_dsi_driver_init);
... ...
module_init(mdss_dsi_ctrl_driver_init);

问题点:在执行时,发现会优先执行原始文件定义的这两个,即使我把module_init(mdss_dsi_bl_driver_init)的部分提到最前面也是一样的。无奈只好寻求更高优先级的方法。

二、module_init的原始定义

    可以发现,module_init的定义是在init.h (kernel\include\linux)中。

#define __initcall(fn) device_initcall(fn)
... ...

/**
 * 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_init仅仅是个宏,实际执行的是__initcall,而__initcall也是个宏,最终执行的是device_initcall

    我们就来看下定义device_initcall的地方:

/*
 * 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)    //device_initcall也是个宏,但是我们发现,__define_initcall不同之处是第二个参数。由上到下依次增加
#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,再看下__define_initcall的定义:

/* initcalls are now grouped by functionality into separate 
 * subsections. Ordering inside the subsections is determined
 * by link order. 
 * For backwards compatibility, initcall() puts the call in 
 * the device init subsection.
 *
 * The `id' arg to __define_initcall() is needed so that multiple initcalls
 * can point at the same handler without causing duplicate-symbol build errors.
 */

#define __define_initcall(fn, id) \
	static initcall_t __initcall_##fn##id __used \
	__attribute__((__section__(".initcall" #id ".init"))) = fn; \
	LTO_REFERENCE_INITCALL(__initcall_##fn##id)

   从这里可以看到__define_initcall把传给module_init的函数名组装成以__initcall为前缀的、以6为后缀的函数名,并把这个函数定义到代码段.initcall6.init里面。

   只能再往下追,再来看看".initcall" #id ".init",它在kernel/msm-3.18/include/asm-generic/vmlinux.lds.h中:

        VMLINUX_SYMBOL(__initcall_start) = .;			\
		*(.initcallearly.init)					\
		INIT_CALLS_LEVEL(0)					\
		INIT_CALLS_LEVEL(1)					\
		INIT_CALLS_LEVEL(2)					\
		INIT_CALLS_LEVEL(3)					\
		INIT_CALLS_LEVEL(4)					\
		INIT_CALLS_LEVEL(5)					\
		INIT_CALLS_LEVEL(rootfs)				\
		INIT_CALLS_LEVEL(6)					\
		INIT_CALLS_LEVEL(7)					\
		VMLINUX_SYMBOL(__initcall_end) = .;
                __initcall_start = .;
                     INITCALLS
              __initcall_end = .;
              __con_initcall_start = .;
                     *(.con_initcall.init)
              __con_initcall_end = .;
              __security_initcall_start = .;
                     *(.security_initcall.init)
              __security_initcall_end = .;

到这可以确认对应的数字0是最高优先级执行的,7是最低优先级执行。对于我们来说只需要比6高就可以了。大家可以根据自己的需要在driver中去执行不同的方法:

pure_initcall(fn)			
core_initcall(fn)			
core_initcall_sync(fn)		
postcore_initcall(fn)		
postcore_initcall_sync(fn)	
arch_initcall(fn)			
arch_initcall_sync(fn)		
subsys_initcall(fn)			
subsys_initcall_sync(fn)	
fs_initcall(fn)				
fs_initcall_sync(fn)		
rootfs_initcall(fn)			
device_initcall(fn)			
device_initcall_sync(fn)	
late_initcall(fn)			
late_initcall_sync(fn)

 

 

参考:http://blog.chinaunix.net/uid-27664726-id-4243961.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章