ARM-Linux移植之(三)——init进程启动流程分析

发布时间:2024-07-15  

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


首先看init_main函数


int init_main(int argc, char **argv);

int init_main(int argc, char **argv)

{

……………………………..

……………………………..

//初始化控制台

console_init();

………………………………


if (argc > 1

&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))

) {

new_init_action(RESPAWN, bb_default_login_shell, "");

} else {

//因为我们启动的init进程没有任何参数,所有argc==1,执行的是这一句

parse_inittab();

}

…………………………………………

…………………………………………

run_actions(SYSINIT); //运行inittab配置文件中acthion为SYSINIT的进程

run_actions(WAIT); //运行inittab配置文件中action为WAIT的进程



run_actions(ONCE); //运行inittba配置文件中action为ONCE的进程

………………………………………………

while (1) {

/*

运行inittab配置文件中action为RESPAWN和ASKFIRST的进程,一旦退出则重新启动

*/

run_actions(RESPAWN);

run_actions(ASKFIRST);


wpid = wait(NULL);

while (wpid > 0) {

a->pid = 0;

}

wpid = waitpid(-1, NULL, WNOHANG);

}

}


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


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


:::


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


runlevels 这个参数完全忽略


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


process 就是要启动的进程。


 


下面来看prase_inittab这个函数


static void parse_inittab(void)

{

…………………………………………………

…………………………………………………


/*INITTAB是一个宏 #define INITTAB      "/etc/inittab"

可以看得出来它打开了/etc/inittab这个文件*/


file = fopen(INITTAB, "r");


//如果没有这个文件,则调用new_init_action进行一些默认的操作

if (file == NULL) {

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

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

if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");

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

new_init_action(ASKFIRST, bb_default_login_shell, "");

new_init_action(ASKFIRST, bb_default_login_shell, VC_2);

new_init_action(ASKFIRST, bb_default_login_shell, VC_3);

new_init_action(ASKFIRST, bb_default_login_shell, VC_4); new_init_action(SYSINIT, INIT_SCRIPT, "");


return;

}

…………………………………………………

…………………………………………………

/*果inittab文件里面有内容就将里面的内容一行一行读出来,然后调用new_init_action进行操作*/

while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {

/* Ok, now process it */

for (a = actions; a->name != 0; a++) {

if (strcmp(a->name, action) == 0) {

if (*id != '') {

if (strncmp(id, "/dev/", 5) == 0)

id += 5;

strcpy(tmpConsole, "/dev/");

safe_strncpy(tmpConsole + 5, id,

sizeof(tmpConsole) - 5);

id = tmpConsole;

}

new_init_action(a->action, command, id);

break;

}

}

…………………………………………………

…………………………………………………

}

fclose(file);

}


这个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的进程,有退出的则重新执行。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>