いくつかのXXX_initcallマクロ研究doc

64906 ワード

引用する
          (bootinfo.c),        :
232 core_initcall(bootinfo_init);
 
607 subsys_initcall(gpiolib_debugfs_init)

 
4549 module_init(pxa3xx_nand_init);
built-in249 #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バージョン.