zoukankan      html  css  js  c++  java
  • ARM-Linux移植之(三)——init进程启动流程分析

    我们通常使用Busybox来构建根文件系统的必要的应用程序。Busybox通过传入的参数来决定执行何种操作。当init进程启动时,实际上调用的是Busybox的init_main()函数,下面我们来分析这个函数,看init进程究竟是怎样一个流程。我分析的Busybox源码是1.7.0版本的,其他版本会略有不同。部分代码省略我们只看关键性代码。

     

    首先看init_main函数

     

    [cpp] view plain?
    1. 01.int init_main(int argc, char **argv);    
    2. 02.int init_main(int argc, char **argv)    
    3. 03.{    
    4. 04.    ……………………………..    
    5. 05.    ……………………………..    
    6. 06.    //初始化控制台    
    7. 07.    console_init();    
    8. 08.    ………………………………    
    9. 09.    
    10. 10.    if (argc > 1    
    11. 11.     && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))    
    12. 12.    ) {    
    13. 13.        new_init_action(RESPAWN, bb_default_login_shell, "");    
    14. 14.    } else {    
    15. 15.        //因为我们启动的init进程没有任何参数,所有argc==1,执行的是这一句    
    16. 16.        parse_inittab();    
    17. 17.    }    
    18. 18.    …………………………………………    
    19. 19.    …………………………………………    
    20. 20.    run_actions(SYSINIT);   //运行inittab配置文件中acthion为SYSINIT的进程    
    21. 21.    run_actions(WAIT);  //运行inittab配置文件中action为WAIT的进程    
    22. 22.    
    23. 23.    
    24. 24.    run_actions(ONCE);  //运行inittba配置文件中action为ONCE的进程    
    25. 25.    ………………………………………………    
    26. 26.    while (1) {    
    27. 27.        /*   
    28. 28.        运行inittab配置文件中action为RESPAWN和ASKFIRST的进程,一旦退出则重新启动   
    29. 29.        */    
    30. 30.        run_actions(RESPAWN);       
    31. 31.        run_actions(ASKFIRST);    
    32. 32.    
    33. 33.        wpid = wait(NULL);    
    34. 34.        while (wpid > 0) {    
    35. 35.                    a->pid = 0;    
    36. 36.            }    
    37. 37.            wpid = waitpid(-1, NULL, WNOHANG);    
    38. 38.            
    39. 39.    }    
    40. 40.}    


     

    parse_inittab实际上对/etc/inittab文件里面的配置进行解释,如果没有,则设置一些默认设置。

    我们先来看看这个inittab这个文件里面的配置格式,这个在busybox文件里面的inittab文件里面有说明

    <id>:<runlevels>:<action>:<process>

    id表示输出输入设备,这个不需要设置,因为/etc/console已经设为标准输入输出了,如不设置,则从控制台输入输出。

    runlevels 这个参数完全忽略

    action 运行时机,它表示inittab解释后的运行顺序,它有sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, andshutdown.这个值可选择。

    process 就是要启动的进程。

     

    下面来看prase_inittab这个函数

    [cpp] view plain?
    1. 01.static void parse_inittab(void)    
    2. 02.{    
    3. 03.…………………………………………………    
    4. 04.…………………………………………………    
    5. 05.    
    6. 06.    /*INITTAB是一个宏 #define INITTAB      "/etc/inittab"      
    7. 07.    可以看得出来它打开了/etc/inittab这个文件*/    
    8. 08.    
    9. 09.    file = fopen(INITTAB, "r");    
    10. 10.    
    11. 11.    //如果没有这个文件,则调用new_init_action进行一些默认的操作    
    12. 12.    if (file == NULL) {    
    13. 13.        new_init_action(CTRLALTDEL, "reboot""");    
    14. 14.        new_init_action(SHUTDOWN, "umount -a -r""");    
    15. 15.        if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a""");    
    16. 16.        new_init_action(RESTART, "init""");    
    17. 17.        new_init_action(ASKFIRST, bb_default_login_shell, "");    
    18. 18.        new_init_action(ASKFIRST, bb_default_login_shell, VC_2);    
    19. 19.        new_init_action(ASKFIRST, bb_default_login_shell, VC_3);    
    20. 20.        new_init_action(ASKFIRST, bb_default_login_shell, VC_4);                         new_init_action(SYSINIT, INIT_SCRIPT, "");    
    21. 21.    
    22. 22.        return;    
    23. 23.    }    
    24. 24.    …………………………………………………    
    25. 25.…………………………………………………    
    26. 26.        /*果inittab文件里面有内容就将里面的内容一行一行读出来,然后调用new_init_action进行操作*/    
    27. 27.    while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {    
    28. 28.        /* Ok, now process it */    
    29. 29.        for (a = actions; a->name != 0; a++) {    
    30. 30.            if (strcmp(a->name, action) == 0) {    
    31. 31.                if (*id != '') {    
    32. 32.                    if (strncmp(id, "/dev/", 5) == 0)    
    33. 33.                        id += 5;    
    34. 34.                    strcpy(tmpConsole, "/dev/");    
    35. 35.                    safe_strncpy(tmpConsole + 5, id,    
    36. 36.                        sizeof(tmpConsole) - 5);    
    37. 37.                    id = tmpConsole;    
    38. 38.                }    
    39. 39.                new_init_action(a->action, command, id);    
    40. 40.                break;    
    41. 41.            }    
    42. 42.        }    
    43. 43.    …………………………………………………    
    44. 44.…………………………………………………    
    45. 45.    }    
    46. 46.    fclose(file);    
    47. 47.}    


     

    这个new_init_action函数,它实际上是将inittab里面的action相同的操作串成一个链表。

    下面我们再来分析init_main执行prase_inittab之后执行的操作

    可以看出init_main执行prase_initab对inittab文件里面的配置进行解释之后,会先执行运行时机为SYSINIT的进程,让执行WAIT时机的,接着是ONCE的,然后在一个while(1)函数里面运行RESPAWN和ASKFIRST时机的,一旦这两个时机里面的进程被杀死,就会把他们的pid赋为0,然后跳到while(1)函数的开始处又去启动他们。所有说运行时机为RESPAWN和ASKFIRST的进程永远无法杀死,除非reboot或者shutdown。

     

    下面我们来总结一下init进程的启动过程
    1.初始化控制台
    2.解释inittab
    3.执行inittab运行时机为SYSINIT的进程
    4.执行inittab运行时机为WAIT的进程
    5.执行inittab运行时机为ONCE的进程
    6.执行inittab运行时机为RESPAWN和ASKFRIST的进程,有退出的则重新执行。


  • 相关阅读:
    js-jQuery对象与dom对象相互转换
    django模板{%for%}中的forloop的应用
    ubuntu MySQL数据库输入中文乱码 解决方案
    多线程下的神奇的IOCP
    类库服务寄宿到WebHost
    细说Asp.Net WebAPI消息处理管道
    项目发布Debug和Release版的区别
    linux yum命令详解
    Linux系统如何查看版本信息
    Linux查看物理CPU个数、核数、逻辑CPU个数
  • 原文地址:https://www.cnblogs.com/alan666/p/8312461.html
Copyright © 2011-2022 走看看