• 内核启动流程3--Busybox的init进程


    Busybox是用来制作文件系统的一个工具集,可以用来替换GNU fileutils shellutils等工具集,它为各种小型的或者嵌入式系统提供了比较完全的工具集。

    它提供的核心程序中包括了用户空间的init进程。用户空间的init进程是整个系统启动流程的最后一个阶段,经过该进程的初始化,整个系统进入服务状态,提供诸如系统调用、任务管理服务及设备管理等服务。

    1)init进程启动流程

    busybox中实现的init进程一般放在开发板的"/sbin"目录下。

    busybox的init进程会根据配置文件决定启动哪些程序,如执行某些脚本、启动shell、运行用户指定的程序等。总之,该init进程将成为后续所有进程的发起者,如在init进程启动"/bin/sh"程序后,才能在控制台上输入各种命令

    busybox的init程序对应代码在busybox的init/init.c下,其初始化流程如下

    其中与构建根文件系统关系密切的是控制台的初始化、对inittab文件的解释及执行。

    2)添加初始化活动

    init进程的初始化任务被分解为一系列初始化活动来完成,busybox定义了8种初始化活动,

    Sysinit:为init进程提供初始化命令脚本的路径。

    Wait:告诉init进程必须等到相应的进程执行完成之后,才能继续执行。

    Once:仅执行相应的进程一次,而且不会等待它执行完成。

    Respawn:当相应的进程终止执行时,重新启动该进程。

    Askfirst:与respawn类似,不过init进程先输出“please press enter to active this console”,等用户按回车键之后,才启动子进程。

    Shutdown:当系统关机时,执行相应的进程。

    Restart:当init进程重新启动时,执行相应的进程,通常此处执行的进程就是init本身。

    Ctrlatldel:当按下crtl+alt_delete组合键时,执行相应的进程

    init进程中需要添加的活动,通常被写到inittab文件中,inittab文件通常位于根文件系统的"/etc"目录下,其中每一条配置信息定义一个初始化活动。格式如下:

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

    inittab中的每个条目有4个字段,各字段间由冒号分开。

    <id>:表示该进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。

    <runlevels>:对于busybox提供的init程序,这个字段没有意义,可以省略

    <action>:表示init进程如何控制该子进程

    <process>:要执行的进程,它可以是可执行程序,也可以是脚本

    一个简单的inittab示例:

    ::sysinit:/etc/init.d/rcS

    ::askfirst:-/bin/sh

    ::ctrllaltdel:/sbin/reboot

    ::shutdown:/bin/umount -a -r

    在init_main()函数中调用parse_inittab()函数解析inittab,也正是在该函数中完成向init进程添加活动的任务。尽管没有inittab文件,parse_inittab()中也会添加默认的活动,如下

    static void parse_inittab(void)

    {

      #if ENABLE_FEATURE_USE_INITTAB

      char *token[4];

      parser_t *parser = config_open2("/etc/inittab",fopen_for_read);

      if(parser == NULL)

      #endif

      {

        /*No inittab file--set up some default behavior*/

        /*Reboot on Ctrl-Alt-Del*/

        new_init_action(CTRLALTDEL,"reboot","");

        /*Umount all filesystems on halt/reboot*/

        new_init_action(SHUTDOWN,"umount -a -r","");

        new_init_action(RESTART,"init","");

        /*sysinit*/

        new_init_action(SYSINIT,INIT_SCRIPT,"");

        return;

      }

    }

    new_init_action函数的三个参数分别表示活动类型、相关的命令和使用的控制台,若不指定最后一个参数,则表示使用与init进程相同的控制台。

    最后一个新的初始化活动,即当SYSINIT活动发生时,由INIT_SCRIPT确定的脚本被执行。SYSINIT活动表示只在系统初始化阶段被init进程加载一次。INIT_SCRIPT宏的默认值定义如下,BUSYBOX init进程默认的初始化脚本是/etc/init.d/rcS

    #define INITTAB  "/etc/inittab"

    #ifndef INIT_SCRIPT

    #define INIT_SCRIPT  "/etc/init.d/rcS"

    #endif

    parse_inittab()函数的其余代码解析inittab文件的具体内容,最终根据Inittab中给定的配置,向init进程添加各项活动。

    3)执行初始化活动

    init进程解析inittab后开始执行各类初始化活动。它通过run_actions()函数执行指定类型的初始化活动,并为符合条件的活动,执行其 相关命令。init进程各类初始化活动的执行顺序如下:

    /*First run the sysinit command*/

    run_actions(SYSINIT);

    /*Next run anything that wants to block*/

    run_actions(WAIT);

    /*Next run anything to be run ony once*/

    run_actions(ONCE);

    .....

    /*Now run the looping stuff for the rest of forever*/

    while(1)

    {

      /*run the respawn/askfirst stuff*/

      run_actions(RESPAWN|ASKFIRST);

      /*Don't consume all CPU time--sleep a bit*/

      sleep(1);

      /*wait for any child process to exit*/

      wpid = wait(NULL);

      while(wpid>0)

      {

        /*Find out who died and clean up their corpse*/

        .....

      }

    }

    从上面的代码可以看出,活动的执行顺序如下:

    1)执行系统初始化脚本,默认为/etc/init.d/rcS,活动类型为SYSINIT;

    2)执行所有将会导致阻塞的初始化活动对应的命令,活动类型是WAIT;

    3)执行所有一次执行的初始化活动的命令,活动类型是ONCE;

    完成以上工作后,init循环执行以下任务:

    1)执行所有中止后必须重启的活动命令,类型是RESPAWN。

    2)执行所有中止后必须重启,但必须先询问的活动命令,类型是ASKFIRST。

    3)等待子进程推出。

  • 相关阅读:
    Vue 学习笔记之 —— 组件(踩了个坑)
    Vue 学习笔记之 —— 表单输入绑定
    js cookie
    python中线程、进程和协程的区别
    设计模式
    Mysql从入门到精通整理
    如何处理缓存失效、缓存穿透、缓存并发等问题
    mysql 查询当天、本周,本月,上一个月的数据
    Mysql分表和分区的区别、分库分表介绍与区别(转)
    mysql数据库死锁的产生原因及解决办法
  • 原文地址:https://www.cnblogs.com/gary-guo/p/6069673.html
Copyright © 2020-2023  润新知