linux 內核中的 __define_initcall

   LINUX內核中有很多的初始化指示標誌postcore_initcall(), arch_initcall(), subsys_initcall(), device_initcall(), etc. 這些起什麼作用呢?查閱源代碼(android goldfish-2.6.29)並搜索網上相關文章,對此做一總結。
  1. 初始化標號

先看這些宏的定義(定義在文件include/linux/init.h中)

  1. #define pure_initcall(fn)               __define_initcall("0",fn,0)  
  2. #define core_initcall(fn)               __define_initcall("1",fn,1)  
  3. #define core_initcall_sync(fn)          __define_initcall("1s",fn,1s)  
  4. #define postcore_initcall(fn)           __define_initcall("2",fn,2)  
  5. #define postcore_initcall_sync(fn)      __define_initcall("2s",fn,2s)  
  6. #define arch_initcall(fn)               __define_initcall("3",fn,3)  
  7. #define arch_initcall_sync(fn)          __define_initcall("3s",fn,3s)  
  8. #define subsys_initcall(fn)             __define_initcall("4",fn,4)  
  9. #define subsys_initcall_sync(fn)        __define_initcall("4s",fn,4s)  
  10. #define fs_initcall(fn)                 __define_initcall("5",fn,5)  
  11. #define fs_initcall_sync(fn)            __define_initcall("5s",fn,5s)  
  12. #define rootfs_initcall(fn)             __define_initcall("rootfs",fn,rootfs)  
  13. #define device_initcall(fn)             __define_initcall("6",fn,6)  
  14. #define device_initcall_sync(fn)        __define_initcall("6s",fn,6s)  
  15. #define late_initcall(fn)               __define_initcall("7",fn,7)  
  16. #define late_initcall_sync(fn)          __define_initcall("7s",fn,7s)  

 

  1. __define_initcall

這些宏都用到了__define_initcall(),再看看它的定義(同樣定義在文件include/linux/init.h中)

  1. #define __define_initcall(level,fn,id) \  
  2.         static initcall_t __initcall_##fn##id __used \  
  3.         __attribute__((__section__(".initcall" level ".init"))) = fn  

 

這其中initcall_t是函數指針,原型如下,

  1. typedef int (*initcall_t)(void);  

 

而屬性 __attribute__((__section__())) 則表示把對象放在一個這個由括號中的名稱所指代的section中。

所以__define_initcall的含義是:

1) 聲明一個名稱爲__initcall_##fn的函數指針;

2) 將這個函數指針初始化爲fn;

3) 編譯的時候需要把這個函數指針變量放置到名稱爲 ".initcall" level ".init"的section中。


3.  放置.initcall.init SECTION

明確了__define_initcall的含義,就知道了是分別將這些初始化標號修飾的函數指針放到各自的section中的。

SECTION“.initcall”level”.init”被放入INITCALLS(include/asm-generic/vmlinux.lds.h)

  1. #define INITCALLS                                                   \  
  2.             *(.initcallearly.init)                                  \  
  3.             VMLINUX_SYMBOL(__early_initcall_end) = .;               \  
  4.             *(.initcall0.init)                                      \  
  5.             *(.initcall0s.init)                                     \  
  6.             *(.initcall1.init)                                      \  
  7.             *(.initcall1s.init)                                     \  
  8.             *(.initcall2.init)                                      \  
  9.             *(.initcall2s.init)                                     \  
  10.             *(.initcall3.init)                                      \  
  11.             *(.initcall3s.init)                                     \  
  12.             *(.initcall4.init)                                      \  
  13.             *(.initcall4s.init)                                     \  
  14.             *(.initcall5.init)                                      \  
  15.             *(.initcall5s.init)                                     \  
  16.             *(.initcallrootfs.init)                                 \  
  17.             *(.initcall6.init)                                      \  
  18.             *(.initcall6s.init)                                     \  
  19.             *(.initcall7.init)                                      \  
  20.             *(.initcall7s.init)  

 

__initcall_start和__initcall_end以及INITCALLS中定義的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在.init段的。

  1. SECTIONS  
  2. {  
  3.         .init : {  
  4.                 __initcall_start = .;  
  5.                         INITCALLS  
  6.                 __initcall_end = .;  
  7.         }  
  8. }  

 

4.   初始化.initcallxx.init裏的函數

而這些SECTION裏的函數在初始化時被順序執行(init內核線程->do_basic_setup()[main.c#778]->do_initcalls())。

程序(init/main.c文件do_initcalls()函數)如下,do_initcalls()把.initcallXX.init中的函數按順序都執行一遍。

  1. for (call = __early_initcall_end; call < __initcall_end; call++)  
  2.         do_one_initcall(*call);  

 

*************************** 本文完 *****************************

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