linux刷新init,linux __init段

__init 收藏

在2.6内核中,initcall.init区段又分成7个子区段,分别是

.initcall1.init

.initcall2.init

.initcall3.init

.initcall4.init

.initcall5.init

.initcall6.init

.initcall7.init

当需要把函数fn放到.initcall1.init区段时,只要声明

core_initcall(fn);

即可。

其他的各个区段的定义方法分别是:

core_initcall(fn) --->.initcall1.init

postcore_initcall(fn) --->.initcall2.init

arch_initcall(fn) --->.initcall3.init

subsys_initcall(fn) --->.initcall4.init

fs_initcall(fn) --->.initcall5.init

device_initcall(fn) --->.initcall6.init

late_initcall(fn) --->.initcall7.init

而与2.4兼容的initcall(fn)则等价于device_initcall(fn)。

各个子区段之间的顺序是确定的,即先调用.initcall1.init中的函数指针

再调用.initcall2.init中的函数指针,等等。

而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。

在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序。

这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。

在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

简单来说是告诉连接器把标记的数据或者函数放到指定段。

linux中把一些启动及初始化时候用的数据用__init标识,然后在适当的时候把它们释放,回收内存。因为初始化初始化一次后就没有用了,这部分内存可以释放了。

说到这个__init,就不能不说module_init,subsys_initcall。

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

file:/include/linux/init.h

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   }

系统是如何执行这些函数呢?

进入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 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值