Linux 內核啟動過程中,init() 函數與 init 進程同名同 PID(1),極易混淆。本文從代碼執行流程、運行特權、代碼來源、演變關係四個維度,徹底釐清二者本質區別與聯繫。
| 維度 | init() 函數 | init 進程 |
|---|---|---|
| 代碼性質 | 內核代碼一部分(init/main.c) | 用戶空間可執行文件(/sbin/init) |
| 運行特權 | 內核態(Ring 0) | 用戶態(Ring 3) |
| 內存空間 | 內核地址空間 | 獨立用戶虛擀地址空間 |
| PID | 1(內核線程階段) | 1(用戶進程階段) |
| 父進程 | 0 號進程(swapper/idle) | 無(系統首個用戶進程) |
0號進程 (swapper/idle, 內核本身)
│ kernel_thread() 創建內核線程
▼
1號內核線程 (無用戶地址空間, 運行在內核態)
│ 直接調用 init() 函數
▼
1號內核進程 (擁有內核地址空間, 仍在內核態)
│ init() 中調用 execve("/sbin/init")
▼
init 進程 (PID 1, 用戶態, 獨立地址空間)
/* arch/x86/kernel/process.c 或 init/main.c */
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
/* init/main.c */
static int __ref init(void *unused)
{
/* ... 大量初始化工作 ... */
lock_kernel();
do_basic_setup(); // 驅動初始化、文件系統等
/* ... */
if (execute_command) {
execve(execute_command, argv_init, envp_init); // 執行 /sbin/init
} else {
/* 嘗試多個默認路徑 */
execve("/sbin/init", argv_init, envp_init);
execve("/etc/init", argv_init, envp_init);
execve("/bin/init", argv_init, envp_init);
execve("/bin/sh", argv_init, envp_init);
}
panic("No init found");
}
/sbin/init ELF 文件到用戶地址空間sys_execve 系統調用返回用戶態,EIP 指向 _start (glibc 入口)fork),但 mm_struct 從 NULL 變為有效用戶地址空間
內核 init 線程
│ 執行 ./linuxrc 腳本
▼
linuxrc 最後:execve /sbin/init
│
▼
用戶態 init 進程
│ 解析 /etc/inittab
▼
啟動 rcS、getty、登錄服務...
嵌入式常用 busybox init,inittab 精簡版:
::sysinit:/etc/init.d/rcS
tty0::respawn:/sbin/getty 38400 tty0
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
init() 是內核初始化主函數,完成硬件探測、驅動加載、子系統初始化init 進程是用戶空間祖先進程,負責服務編排、孤兒進程收養、運行級別管理execve 實現「同一 PID、雙重身份」的無縫交接