いくつかのXXX_initcallマクロ研究doc
64906 ワード
引用する
彼らの意思や运行顺番はおおむね分かっているが、もう少し详しく知るつもりだ.そこでコードの追跡を開始します.
do_からinitcalls開始
この関数は、実際には初期関数のリストに従って1つの関数を呼び出すことがわかります.
パラメータinitcallを起動することで価値のある情報を得ることができます.debug=1は、カーネルにこれらの関数の関連(時間、順序など)を印刷させるために使用され、最適化の開始に特に役立ちます.
もう一度見てdo_initcallsが呼び出されたのはいつですか.
kernel_Initは1番プロセスinitの実行関数で、do_が表示されます.initcallsは、システムがinitプロセスに実行された後、ユーザ空間に入る前に呼び出されます.
初期関数のリストを見てみましょう.initcall_startはどのように生成されたのか、検索してみると、リンクファイル:arch/arm/kernel/vmlinux.lds.Sには、
マクロの定義を見てみましょう
いろいろ見てみましょうinitcallマクロの定義:
もう一度見てみようdefine_initcallの定義:
これで、両側がつながった:元のすべてのXXX_initcallマクロで定義された関数は同じ初期化関数リストに格納されますが、異なるマクロで定義された関数は異なる位置に配置され、数字の小さいものが先に呼び出されます.
通常のドライバでは、多くの場合__を使用します.initcallまたはdevice_initcallマクロですが、同じマクロを使用する関数の呼び出し順序はどうですか?これは彼らとのリンク順によってシステムに着くことができます.mapファイルは、リンク後の結果を表示します.たとえば、次のように表示されます.
__initcall_pxafb_init 6は__に並んでいますinitcall_tty_init 6の前です.
コンパイル順序は、ファイル名、ディレクトリ名、さらにはプロファイルを変更した後で変更される可能性がありますので、同類のXX_initcallマクロ間で依存関係が発生します.本当に必要で、使用を考慮することができます_syncバージョン.
(bootinfo.c), :
232 core_initcall(bootinfo_init);
: 607 subsys_initcall(gpiolib_debugfs_init)
:4549 module_init(pxa3xx_nand_init);
(built-in :249 #define module_init(x) __initcall(x);)
彼らの意思や运行顺番はおおむね分かっているが、もう少し详しく知るつもりだ.そこでコードの追跡を開始します.
do_からinitcalls開始
:do_initcalls initcalls, , :
664 static void __init do_initcalls(void)
665 {
666 initcall_t *call;
667 int count = preempt_count();
668
669 for (call = __initcall_start; call < __initcall_end; call++) {
673 unsigned long j, j0 = 0;
674 char *msg = NULL;
675 char msgbuf[40];
676 int result;
677
678 if (initcall_debug) {
686 j0 = jiffies;
687 }
688
689 result = (*call)();
690
691 if (initcall_debug) {
692 j = jiffies - j0;
705 if (j > 1) {
706 printk("initcall 0x%p ran for %d msecs: ",
707 *call, jiffies_to_msecs(j));
708 print_fn_descriptor_symbol("%s()/n",
709 (unsigned long) *call);
710 }
711 }
712
713 if (result && result != -ENODEV && initcall_debug) {
714 sprintf(msgbuf, "error code %d", result);
715 msg = msgbuf;
716 }
717 if (preempt_count() != count) {
718 msg = "preemption imbalance";
719 preempt_count() = count;
720 }
721 if (irqs_disabled()) {
722 msg = "disabled interrupts";
723 local_irq_enable();
724 }
725 if (msg) {
726 printk(KERN_WARNING "initcall at 0x%p", *call);
727 print_fn_descriptor_symbol(": %s()",
728 (unsigned long) *call);
729 printk(": returned with %s/n", msg);
730 }
731 }
732
733 /* Make sure there is no pending stuff from the initcall sequence */
734 flush_scheduled_work();
735 }
この関数は、実際には初期関数のリストに従って1つの関数を呼び出すことがわかります.
パラメータinitcallを起動することで価値のある情報を得ることができます.debug=1は、カーネルにこれらの関数の関連(時間、順序など)を印刷させるために使用され、最適化の開始に特に役立ちます.
もう一度見てdo_initcallsが呼び出されたのはいつですか.
744 static void __init do_basic_setup(void)
745 {
746 /* drivers will send hotplug events */
747 init_workqueues();
748 usermodehelper_init();
749 driver_init();
750 init_irq_proc();
751 do_initcalls();
752 }
821 static int __init kernel_init(void * unused)
822 {
823 lock_kernel();
824 /*
825 * init can run on any cpu.
826 */
827 set_cpus_allowed(current, CPU_MASK_ALL);
828 /*
829 * Tell the world that we're going to be the grim
830 * reaper of innocent orphaned children.
831 *
832 * We don't want people to have to make incorrect
833 * assumptions about where in the task array this
834 * can be found.
835 */
836 init_pid_ns.child_reaper = current;
837
838 cad_pid = task_pid(current);
839
840 smp_prepare_cpus(setup_max_cpus);
841
842 do_pre_smp_initcalls();
843
844 smp_init();
845 sched_init_smp();
846
847 cpuset_init_smp();
848
849 do_basic_setup();
850
851 /*
852 * check if there is an early userspace init. If yes, let it do all
853 * the work
854 */
855
856 if (!ramdisk_execute_command)
857 ramdisk_execute_command = "/init";
858
859 if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
860 ramdisk_execute_command = NULL;
861 prepare_namespace();
862 }
863
864 /*
865 * Ok, we have completed the initial bootup, and
866 * we're essentially up and running. Get rid of the
867 * initmem segments and start the user-mode stuff..
868 */
869 init_post();
870 return 0;
871 }
kernel_Initは1番プロセスinitの実行関数で、do_が表示されます.initcallsは、システムがinitプロセスに実行された後、ユーザ空間に入る前に呼び出されます.
初期関数のリストを見てみましょう.initcall_startはどのように生成されたのか、検索してみると、リンクファイル:arch/arm/kernel/vmlinux.lds.Sには、
51 __initcall_start = .;
52 INITCALLS
53 __initcall_end = .;
:INITCALLS :
328 #define INITCALLS /
329 *(.initcall0.init) /
330 *(.initcall0s.init) /
331 *(.initcall1.init) /
332 *(.initcall1s.init) /
333 *(.initcall2.init) /
334 *(.initcall2s.init) /
335 *(.initcall3.init) /
336 *(.initcall3s.init) /
337 *(.initcall4.init) /
338 *(.initcall4s.init) /
339 *(.initcall5.init) /
340 *(.initcall5s.init) /
341 *(.initcallrootfs.init) /
342 *(.initcall6.init) /
343 *(.initcall6s.init) /
344 *(.initcall7.init) /
345 *(.initcall7s.init)
do_initcalls 。 , freetext , XXX_initcall , 。
マクロの定義を見てみましょう
いろいろ見てみましょうinitcallマクロの定義:
176 #define pure_initcall(fn) __define_initcall("",fn,0)
177
178 #define core_initcall(fn) __define_initcall("1",fn,1)
179 #define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
180 #define postcore_initcall(fn) __define_initcall("2",fn,2)
181 #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
182 #define arch_initcall(fn) __define_initcall("3",fn,3)
183 #define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
184 #define subsys_initcall(fn) __define_initcall("4",fn,4)
185 #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
186 #define fs_initcall(fn) __define_initcall("5",fn,5)
187 #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
188 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
189 #define device_initcall(fn) __define_initcall("6",fn,6)
190 #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
191 #define late_initcall(fn) __define_initcall("7",fn,7)
192 #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
193
194 #define __initcall(fn) device_initcall(fn)
もう一度見てみようdefine_initcallの定義:
166 #define __define_initcall(level,fn,id) /
167 static initcall_t __initcall_##fn##id __used /
168 __attribute__((__section__(".initcall" level ".init"))) = fn
これで、両側がつながった:元のすべてのXXX_initcallマクロで定義された関数は同じ初期化関数リストに格納されますが、異なるマクロで定義された関数は異なる位置に配置され、数字の小さいものが先に呼び出されます.
通常のドライバでは、多くの場合__を使用します.initcallまたはdevice_initcallマクロですが、同じマクロを使用する関数の呼び出し順序はどうですか?これは彼らとのリンク順によってシステムに着くことができます.mapファイルは、リンク後の結果を表示します.たとえば、次のように表示されます.
__initcall_pxafb_init 6は__に並んでいますinitcall_tty_init 6の前です.
コンパイル順序は、ファイル名、ディレクトリ名、さらにはプロファイルを変更した後で変更される可能性がありますので、同類のXX_initcallマクロ間で依存関係が発生します.本当に必要で、使用を考慮することができます_syncバージョン.