您的位置:首页 > 其它

神秘的subsys_initcall【转】

2016-04-13 18:02 176 查看
转自:http://blog.chinaunix.net/uid-12567959-id-161015.html

在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢?让我们来揭开它的神秘面纱。

先来看一段代码:

---------------------------------------------------------------------

include/linux/init.h

174 /*

175 * Early initcalls run before initializing SMP.

176 *

177 * Only for built-in code, not modules.

178 */

179 #define early_initcall(fn) __define_initcall("early",fn,early)

180

181 /*

182 * A "pure" initcall has no dependencies on anything else, and purely

183 * initializes variables that couldn't be statically initialized.

184 *

185 * This only exists for built-in code, not for modules.

186 */

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

188

189 #define core_initcall(fn) __define_initcall("1",fn,1)

190 #define core_initcall_sync(fn) __define_initcall("1s",fn,1s)

191 #define postcore_initcall(fn) __define_initcall("2",fn,2)

192 #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)

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

194 #define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)

195 #define subsys_initcall(fn) __define_initcall("4",fn,4)

196 #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)

197 #define fs_initcall(fn) __define_initcall("5",fn,5)

198 #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)

199 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)

200 #define device_initcall(fn) __define_initcall("6",fn,6)

201 #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)

202 #define late_initcall(fn) __define_initcall("7",fn,7)

203 #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

---------------------------------------------------------------------

类似于subsys_initcall()还有很多,但它们都依赖于__define_initcall(),再来看__define_initcall()的定义:

---------------------------------------------------------------------

include/linux/init.h

131 typedef int (*initcall_t)(void);

165 *

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

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

168 */

169

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

171 static initcall_t __initcall_##fn##id __used \

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

173

---------------------------------------------------------------------

__define_initcall()宏只是定义一个initcall_t类型的静态变量,并且声明要把这个静态变量放在特定的段里而已。上面我们看到initcall_t即是指向一个无参数有int返回值的函数的指针。

许多的子系统都有自己的初始化函数,而这些初始化的函数又根据功能不同被分开在不同的子段里,子段的排列顺序则由链接决定。为了向后兼容,initcall()把调用,也就是一个个指向初始化函数的函数指针放进设备初始化子段里。

在各个平台的链接脚本文件arch/xxx/kernel/vmlinux.lds.S中,我们总能看到下面的语句:

INIT_CALLS

这个宏有如下的定义:

---------------------------------------------------------------------

include/asm-generic/vmlinux.lds.h

606 #define INIT_CALLS \

607 VMLINUX_SYMBOL(__initcall_start) = .; \

608 INITCALLS \

609 VMLINUX_SYMBOL(__initcall_end) = .;

---------------------------------------------------------------------

INIT_CALLS即是定义一个新的段,而定义段的字段的任务则由宏INITCALLS完成:

---------------------------------------------------------------------

include/asm-generic/vmlinux.lds.h

585 #define INITCALLS \

586 *(.initcallearly.init) \

587 VMLINUX_SYMBOL(__early_initcall_end) = .; \

588 *(.initcall0.init) \

589 *(.initcall0s.init) \

590 *(.initcall1.init) \

591 *(.initcall1s.init) \

592 *(.initcall2.init) \

593 *(.initcall2s.init) \

594 *(.initcall3.init) \

595 *(.initcall3s.init) \

596 *(.initcall4.init) \

597 *(.initcall4s.init) \

598 *(.initcall5.init) \

599 *(.initcall5s.init) \

600 *(.initcallrootfs.init) \

601 *(.initcall6.init) \

602 *(.initcall6s.init) \

603 *(.initcall7.init) \

604 *(.initcall7s.init)

---------------------------------------------------------------------

而这些初始化函数又是在何时调用的呢?我们看到start_kernel()-> rest_init()-> kernel_init()-> do_basic_setup(void)-> do_initcalls(),而正是do_initcalls()处理了这些初始化函数,其定义为:

---------------------------------------------------------------------

init/main.c

765 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

766

767 static void __init do_initcalls(void)

768 {

769 initcall_t *fn;

770

771 for (fn = __early_initcall_end; fn < __initcall_end; fn++)

772 do_one_initcall(*fn);

773

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

775 flush_scheduled_work();

776 }

---------------------------------------------------------------------

do_initcalls()又调用do_one_initcall()函数类处理这些调用。

---------------------------------------------------------------------

init/main.c

715 static char msgbuf[64];

716 static struct boot_trace_call call;

717 static struct boot_trace_ret ret;

718

719 int do_one_initcall(initcall_t fn)

720 {

721 int count = preempt_count();

722 ktime_t calltime, delta, rettime;

723

724 if (initcall_debug) {

725 call.caller = task_pid_nr(current);

726 printk("calling %pF @ %i\n", fn, call.caller);

727 calltime = ktime_get();

728 trace_boot_call(&call, fn);

729 enable_boot_trace();

730 }

731

732 ret.result = fn();

733

734 if (initcall_debug) {

735 disable_boot_trace();

736 rettime = ktime_get();

737 delta = ktime_sub(rettime, calltime);

738 ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10;

739 trace_boot_ret(&ret, fn);

740 printk("initcall %pF returned %d after %Ld usecs\n", fn,

741 ret.result, ret.duration);

742 }

743

744 msgbuf[0] = 0;

745

746 if (ret.result && ret.result != -ENODEV && initcall_debug)

747 sprintf(msgbuf, "error code %d ", ret.result);

748

749 if (preempt_count() != count) {

750 strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));

751 preempt_count() = count;

752 }

753 if (irqs_disabled()) {

754 strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));

755 local_irq_enable();

756 }

757 if (msgbuf[0]) {

758 printk("initcall %pF returned with %s\n", fn, msgbuf);

759 }

760

761 return ret.result;

762 }

---------------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: