__init

宏定義__init,用於告訴編譯器相關函式或變數僅用於初始化。 編譯器將標__init的所有代碼存在特殊的記憶體段中,初始化結束後就釋放這段記憶體。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dirvers/char/random.c

679 static int __init batch_entropy_init(int size, struct entropy_store *r)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在kernel中有很多__init,這個東東到底是何方神聖呢?且聽小生我一一道來。

下面是其定義:

file:/include/linux/init.h

43 #define __init __attribute__ ((__section__ (".init.text"))) __cold

44 #define __initdata __attribute__ ((__section__ (".init.data")))

45 #define __exitdata __attribute__ ((__section__(".exit.data")))

46 #define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))

也許你會問那 __attribute__ ((__section__ (".init.text"))) __cold是什麼東東阿?

且看 info gcc C Extensions Attribute Syntax

section ("SECTION-NAME")'

Normally, the compiler places the objects it generates in sections

like `data' and `bss'. Sometimes, however, you need additional

sections, or you need certain particular variables to appear in

special sections, for example to map to special hardware. The

`section' attribute specifies that a variable (or function) lives

in a particular section. For example, this small program uses

several specific section names:

struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };

struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };

char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };

int init_data __attribute__ ((section ("INITDATA"))) = 0;

main()

{

/* Initialize stack pointer */

init_sp (stack + sizeof (stack));

/* Initialize initialized data */

memcpy (∈it_data, &data, &edata - &data);

/* Turn on the serial ports */

init_duart (&a);

init_duart (&b);

}

Use the `section' attribute with an _initialized_ definition of a

_global_ variable, as shown in the example. GCC issues a warning

and otherwise ignores the `section' attribute in uninitialized

variable declarations.

You may only use the `section' attribute with a fully initialized

global definition because of the way linkers work. The linker

requires each object be defined once, with the exception that

uninitialized variables tentatively go in the `common' (or `bss')

section and can be multiply "defined". You can force a variable

to be initialized with the `-fno-common' flag or the `nocommon'

attribute.

Some file formats do not support arbitrary sections so the

`section' attribute is not available on all platforms. If you

need to map the entire contents of a module to a particular

section, consider using the facilities of the linker instead.

簡單來說是指示gcc把標記的數據或者函式放到指定sector。

linux中把一些啟動及初始化時候用的數據用__init標識,然後在適當的時候把它們釋放,回收記憶體。

說到這個__init,就不能不說module_init,subsys_initcall。

在init.h中我們能夠找到 #define subsys_initcall(fn) __define_initcall("4",fn,4)

又是一個宏定義,簡直是無極中的圓環套圓環之城阿。

file:/include/linux/init.h

100 /* initcalls are now grouped by functionality into separate

101 * subsections. Ordering inside the subsections is determined

102 * by link order.

103 * For backwards compatibility, initcall() puts the call in

104 * the device init subsection.

105 *

106 * The `id' arg to __define_initcall() is needed so that multiple initcalls

107 * can point at the same handler without causing duplicate-symbol build errors.

108 */

109

110 #define __define_initcall(level,fn,id) \

111 static initcall_t __initcall_##fn##id __attribute_used__ \

112 __attribute__((__section__(".initcall" level ".init"))) = fn

subsys_initcall(usb_init)轉換後就變成了 static initcall_t __initcall_usbinit4 __attribute_used__ \

__attribute__((__section__(".initcall 4.init"))) = usb_init

就是把usb_init的函式入口指針存放在.initcall4.init中。

file:/include/asm-generic/vmlinux.lds.h

239 #define INITCALLS \

240 *(.initcall0.init) \

241 *(.initcall0s.init) \

242 *(.initcall1.init) \

243 *(.initcall1s.init) \

244 *(.initcall2.init) \

245 *(.initcall2s.init) \

246 *(.initcall3.init) \

247 *(.initcall3s.init) \

248 *(.initcall4.init) \

249 *(.initcall4s.init) \

250 *(.initcall5.init) \

251 *(.initcall5s.init) \

252 *(.initcallrootfs.init) \

253 *(.initcall6.init) \

254 *(.initcall6s.init) \

255 *(.initcall7.init) \

256 *(.initcall7s.init)

file:/arch/kernel/vmlinux_32.lds.S

144 .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {

145 __initcall_start = .;

146 INITCALLS

147 __initcall_end = .;

148 }

展開

.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {

__initcall_start = .;

*(.initcall0.init) \

*(.initcall0s.init) \

*(.initcall1.init) \

*(.initcall1s.init) \

*(.initcall2.init) \

*(.initcall2s.init) \

*(.initcall3.init) \

*(.initcall3s.init) \

*(.initcall4.init) \

*(.initcall4s.init) \

*(.initcall5.init) \

*(.initcall5s.init) \

*(.initcallrootfs.init) \

*(.initcall6.init) \

*(.initcall6s.init) \

*(.initcall7.init) \

*(.initcall7s.init)

__initcall_end = .;

}

那么系統是如何執行這些函式呢?

此話就長了阿~ 話說盤古開天嫦娥姐姐補天后我們來到了main.c這個linux中舉足輕重的檔案

進入start_kernel

start_kernel -->rest_init() -->kernel_init() --> do_basic_setup() -->do_initcalls()

這個do_initcalls()就是調用這些函式的地方。

file:/init/main.c

662 static void __init do_initcalls(void)

663 {

664 initcall_t *call;

665 int count = preempt_count();

666

667 for (call = __initcall_start; call < __initcall_end; call++) {

668 ktime_t t0, t1, delta;

669 char *msg = NULL;

670 char msgbuf[40];

671 int result;

672

673 if (initcall_debug) {

674 printk("Calling initcall 0x%p", *call);

675 print_fn_descriptor_symbol(": %s()",

676 (unsigned long) *call);

677 printk("\n");

678 t0 = ktime_get();

679 }

680

681 result = (*call)();

682

683 if (initcall_debug) {

684 t1 = ktime_get();

685 delta = ktime_sub(t1, t0);

686

687 printk("initcall 0x%p", *call);

688 print_fn_descriptor_symbol(": %s()",

689 (unsigned long) *call);

690 printk(" returned %d.\n", result);

691

692 printk("initcall 0x%p ran for %Ld msecs: ",

693 *call, (unsigned long long)delta.tv64 >> 20);

694 print_fn_descriptor_symbol("%s()\n",

695 (unsigned long) *call);

696 }

697

698 if (result && result != -ENODEV && initcall_debug) {

699 sprintf(msgbuf, "error code %d", result);

700 msg = msgbuf;

701 }

702 if (preempt_count() != count) {

703 msg = "preemption imbalance";

704 preempt_count() = count;

705 }

706 if (irqs_disabled()) {

707 msg = "disabled interrupts";

708 local_irq_enable();

709 }

710 if (msg) {

711 printk(KERN_WARNING "initcall at 0x%p", *call);

712 print_fn_descriptor_symbol(": %s()",

713 (unsigned long) *call);

714 printk(": returned with %s\n", msg);

715 }

716 }

717

718 /* Make sure there is no pending stuff from the initcall sequence */

719 flush_scheduled_work();

720 }

相關詞條

熱門詞條

聯絡我們