ARM-Linux移植之(三)——init進程啓動流程分析

ARM-Linux移植之(三)——init進程啓動流程分析

K-Style

 

轉載請註明來自於衡陽師範學院08電2  K-Style  http://blog.csdn.net/ayangke,QQ:843308498 郵箱:[email protected]

 

我們通常使用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>:<runlevels>:<action>:<process>

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 != '\0') {
					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的進程,有退出的則重新執行。




發佈了67 篇原創文章 · 獲贊 9 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章