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

 

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