看驅動的時候,時常會有如下代碼:
.remove = __devexit_p(XX_exit),
這裏的__devexit_p有什麼作用呢?
我在include/linux/init.h中找到了它的定義:
/* Functions marked as __devexit may be discarded at kernel link time, depending
on config options. Newer versions of binutils detect references from
retained sections to discarded sections and flag an error. Pointers to
__devexit functions must use __devexit_p(function_name), the wrapper will
insert either the function_name or NULL, depending on the config options.
*/
#if defined(MODULE) || defined(CONFIG_HOTPLUG)
#define __devexit_p(x) x
#else
#define __devexit_p(x) NULL
#endif
注釋已經說的狠明白了吧!
在內核裏經常可以看到__init, __devinit這樣的語句,這都是在init.h中定義的宏,gcc在編譯時會將被修飾的內容放到這些巨集所代表的section。
其典型的定義如下:
- #define __init __section(.init.text) __cold notrace
- #define __initdata __section(.init.data)
- #define __initconst __section(.init.rodata)
- #define __exitdata __section(.exit.data)
- #define __exit_call __used __section(.exitcall.exit)
其典型用法如下:
- static int __init xxx_drv_init(void)
- {
- return pci_register_driver(&xxx_driver);
- }
根據上面的定義與用法,xxx_drv_init()函數將會被link到.init.text段。
之所以加入這樣的宏,原因有2:
1, 一部分內核初始化機制依賴與它。如kernel將初始化要執行的init函數,分為7個級別,core_initcall, postcore_initcall, arch_initcall, subsys_initcall, fs_iitcall, device_initcall, late_initcall。這7個級別優先順序遞減,即先執行core_initcall, 最後執行late_initcall。通過使用文中提到的宏,gcc會將初始化代碼按下面的結構安排:
在內核初始化時,從__initcall_start到__initcall_end之間的initcall被一次執行。
2,提高系統效率
初始化代碼的特點是,在系統啟動時運行,且一旦運行後馬上推出記憶體,不再佔用記憶體。
================================================================================
常用的宏:
- __init,標記內核啟動時所用的初始化代碼,內核啟動完成後就不再使用。其所修飾的內容被放到.init.text section中。
- __exit,標記模組退出代碼,對非模組無效
- __initdata,標記內核啟動時所用的初始化資料結構,內核啟動完成後不再使用。其所修飾的內容被放到.init.data section中。
- __devinit,標記設備初始化所用的代碼
- __devinitdata,標記設備初始化所用的資料結構
- __devexit,標記設備移除時所用的代碼
- xxx_initcall,7個級別的初始化函數
==================================================================================
driver中的使用:
- module_init, module_exit函數所調用的函數,需要分別用__init和__exit來標記
- pci_driver資料結構不需要標記
- probe和remove函數用__devinit和__devexit來標記
- 如果remove使用__devexit標記,則在pci_drvier結構中要用__devexit_p(remove)來引用remove函數
- 如果不確定需不需要添加巨集,則不要添加
原文網址
留言列表