神秘的subsys_initcall【转】
轉(zhuǎn)自:http://blog.chinaunix.net/uid-12567959-id-161015.html
在內(nèi)核代碼里到處都能看到這個(gè)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()宏只是定義一個(gè)initcall_t類型的靜態(tài)變量,并且聲明要把這個(gè)靜態(tài)變量放在特定的段里而已。上面我們看到initcall_t即是指向一個(gè)無參數(shù)有int返回值的函數(shù)的指針。
?
許多的子系統(tǒng)都有自己的初始化函數(shù),而這些初始化的函數(shù)又根據(jù)功能不同被分開在不同的子段里,子段的排列順序則由鏈接決定。為了向后兼容,initcall()把調(diào)用,也就是一個(gè)個(gè)指向初始化函數(shù)的函數(shù)指針放進(jìn)設(shè)備初始化子段里。
?
在各個(gè)平臺(tái)的鏈接腳本文件arch/xxx/kernel/vmlinux.lds.S中,我們總能看到下面的語句:
INIT_CALLS
這個(gè)宏有如下的定義:
---------------------------------------------------------------------
include/asm-generic/vmlinux.lds.h
606 #define INIT_CALLS???????????????????????????????????????????\
607?????????????????VMLINUX_SYMBOL(__initcall_start) = .;????????\
608?????????????????INITCALLS????????????????????????????????????\
609?????????????????VMLINUX_SYMBOL(__initcall_end) = .;
---------------------------------------------------------------------
INIT_CALLS即是定義一個(gè)新的段,而定義段的字段的任務(wù)則由宏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)
---------------------------------------------------------------------
?
而這些初始化函數(shù)又是在何時(shí)調(diào)用的呢?我們看到start_kernel()-> rest_init()-> kernel_init()-> do_basic_setup(void)-> do_initcalls(),而正是do_initcalls()處理了這些初始化函數(shù),其定義為:
---------------------------------------------------------------------
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()又調(diào)用do_one_initcall()函數(shù)類處理這些調(diào)用。
---------------------------------------------------------------------
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 }
---------------------------------------------------------------------
總結(jié)
以上是生活随笔為你收集整理的神秘的subsys_initcall【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解移动开发的模板复用机制
- 下一篇: 数据仓库专题(23):总线矩阵的另类应用