arch_initcall与do_initcalls

在Linux中的许多地方经常可以看到arch_initcall的使用,arch_initcall究竟是干什么用的呢?查找整个工程可以在…/kernel/linux/init.h文件中找到arch_initcall的定义:

#define arch_initcall(fn)		__define_initcall("3",fn,3)

所以,对arch_initcall的使用就是对__define_initcall的使用,继续查找下去同样能够找到__define_initcall的定义:

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

到这,其实不难发现__define_initcall其实就是将fn(也就是某个函数)定义在(".initcall" level “.init”)这样一个段中,而__define_initcall还有另外两个参数level与id,其作用分别是设置函数链接先后顺序和设置序列号。对于链接先后顺序,我们其实可以查看链接脚本更直观的理解,以下是有关段的定义:
在这里插入图片描述可以清楚的看到(".initcall" level “.init”)这样的段共有17个,它们位置不一样导致执行时的顺序也将会不同,所以level这个参数其实就是执行时重要程度,越重要的将会越早执行,比如说凡是使用arch_initcall的初始化代码等级都为3,对于其他等级内核又有相应的定义,它们都在…/kernel/linux/init.h文件中:

#define pure_initcall(fn)		__define_initcall("0",fn,0)

#define core_initcall(fn)		__define_initcall("1",fn,1)
#define core_initcall_sync(fn)		__define_initcall("1s",fn,1s)
#define postcore_initcall(fn)		__define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)	__define_initcall("2s",fn,2s)
#define arch_initcall(fn)		__define_initcall("3",fn,3)
#define arch_initcall_sync(fn)		__define_initcall("3s",fn,3s)
#define subsys_initcall(fn)		__define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)	__define_initcall("4s",fn,4s)
#define fs_initcall(fn)			__define_initcall("5",fn,5)
#define fs_initcall_sync(fn)		__define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)		__define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)		__define_initcall("6",fn,6)
#define device_initcall_sync(fn)	__define_initcall("6s",fn,6s)
#define late_initcall(fn)		__define_initcall("7",fn,7)
#define late_initcall_sync(fn)		__define_initcall("7s",fn,7s)

这样,编译完成后,所有的初始化代码都将会按重要程度依次牌坊好,但另一个问题又出现了,内核是在什么地方依次执行的这些代码呢?这时候就要谈do_initcalls函数了,其被调用的过程为start_kernel -> rest_init-> kernel_init -> do_basic_setup-> do_initcalls。这个函数内容如下:

static void __init do_initcalls(void)
{
	initcall_t *fn;

	for (fn = __early_initcall_end; fn < __initcall_end; fn++)
		do_one_initcall(*fn);

	/* Make sure there is no pending stuff from the initcall sequence */
	flush_scheduled_work();
}

我们从这段代码中可以很直观的发现这个函数相当于遍历了(".initcall" level “.init”)这个段,依次通过do_one_initcall函数调用相应的初始化代码,至此,arch_initcall与do_initcalls两者的关系便建立了起来。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值