以linux4.19内核linux系统中第一个进程。
执行shell指令 ps -ef
结果如下:
xxx@xxx-virtual-machine:~$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 20:55 ? 00:00:02 /sbin/init splash
root 2 0 0 20:55 ? 00:00:00 [kthreadd]
root 3 2 0 20:55 ? 00:00:00 [rcu_gp]
root 4 2 0 20:55 ? 00:00:00 [rcu_par_gp]
root 5 2 0 20:55 ? 00:00:00 [slub_flushwq]
root 6 2 0 20:55 ? 00:00:00 [netns]
root 8 2 0 20:55 ? 00:00:00 [kworker/0:0H-events_highpri]
root 10 2 0 20:55 ? 00:00:00 [mm_percpu_wq]
root 11 2 0 20:55 ? 00:00:00 [rcu_tasks_rude_]
root 12 2 0 20:55 ? 00:00:00 [rcu_tasks_trace]
root 13 2 0 20:55 ? 00:00:00 [ksoftirqd/0]
root 14 2 0 20:55 ? 00:00:00 [rcu_sched]
root 15 2 0 20:55 ? 00:00:00 [migration/0]
root 16 2 0 20:55 ? 00:00:00 [idle_inject/0]
root 17 2 0 20:55 ? 00:00:00 [kworker/0:1-events]
root 18 2 0 20:55 ? 00:00:00 [cpuhp/0]
root 19 2 0 20:55 ? 00:00:00 [cpuhp/1]
root 20 2 0 20:55 ? 00:00:00 [idle_inject/1]
root 21 2 0 20:55 ? 00:00:00 [migration/1]
...
可以看到第一个进程PID为1,拉起第一个进程的指令为/sbin/init splash
内核启动流程:
start_kernel (init/main.c)
kernel_init
kernel_init函数如下:
static int __ref kernel_init(void *unused)
{...if (ramdisk_execute_command) {ret = run_init_process(ramdisk_execute_command);if (!ret)return 0;pr_err("Failed to execute %s (error %d)\n", ramdisk_execute_command, ret);}/** We try each of these until one succeeds.** The Bourne shell can be used instead of init if we are* trying to recover a really broken machine.*/if (execute_command) {ret = run_init_process(execute_command);if (!ret)return 0;panic("Requested init %s failed (error %d).",execute_command, ret);}if (!try_to_run_init_process("/sbin/init") ||!try_to_run_init_process("/etc/init") ||!try_to_run_init_process("/bin/init") ||!try_to_run_init_process("/bin/sh"))return 0;panic("No working init found. Try passing init= option to kernel. ""See Linux Documentation/admin-guide/init.rst for guidance.");}
上面代码片中的两个变量:ramdisk_execute_command 和 execute_command。
其定义如下:
static int __init init_setup(char *str)
{unsigned int i;execute_command = str;/** In case LILO is going to boot us with default command line,* it prepends "auto" before the whole cmdline which makes* the shell think it should execute a script with such name.* So we ignore all arguments entered _before_ init=... [MJ]*/for (i = 1; i < MAX_INIT_ARGS; i++)argv_init[i] = NULL;return 1;
}
__setup("init=", init_setup);static int __init rdinit_setup(char *str)
{unsigned int i;ramdisk_execute_command = str;/* See "auto" comment in init_setup */for (i = 1; i < MAX_INIT_ARGS; i++)argv_init[i] = NULL;return 1;
}
__setup("rdinit=", rdinit_setup);使用__setup("init=", init_setup)宏注册了这个函数,这样当内核启动时遇到
init=<command>这样的启动参数时,就会调用init_setup函数进行处理。
-
ramdisk_execute_command
ramdisk_execute_command 变量的值可以通过内核启动参数 rdinit 来设置。在Linux内核引导过程中,如果用户在命令行参数或GRUB等 bootloader配置中指定了类似 rdinit=/path/to/executable 的参数,内核在初始化initrd之后会尝试执行位于指定路径的可执行文件作为初始化脚本或进程。 -
execute_command
类似上面