目录
三个特殊进程
0号进程的产生
内核init进程的产生
内核init进程的作用
用户空间init进程作用
Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)
* idle进程由系统自动创建, 运行在内核态 idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换。
* init进程由idle通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终用户空间 由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程 Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。
* kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理 它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthread的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程
参考网址:Linux下0号进程的前世(init_task进程)今生(idle进程)
内核中init_task变量就是是进程0使用的进程描述符,也是Linux系统中第一个进程描述符,init_task并不是系统通过kernel_thread的方式(当然更不可能是fork)创建的, 而是由内核黑客静态创建的.
初始化位置:init/init_task.c
/* Initial task structure */ struct task_struct init_task = INIT_TASK(init_task); EXPORT_SYMBOL(init_task);参考网址:Linux下0号进程的前世(init_task进程)今生(idle进程)
rest_init //init/main.c kernel_thread(kernel_init, NULL, CLONE_FS); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
说明:这个函数其实是由0号进程执行的, 他就是在这个函数中, 创建了init进程和kthreadd进程。
参考网址:Linux下1号进程的前世(kernel_init)今生(init进程)
源码
kernel_init //init/main.c ...
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/init.txt for guidance.");
解析 1.ramdisk_execute_command和execute_command ramdisk_execute_command对应uboot的bootargs的"rdinit=...",execute_command对应uboot的bootargs的"init=..."。 一般不使用这两个。 2.依次查找init rdinit=..., init=, /sbin/init, /etc/init, /bin/init/, /bin/sh会依次查找,只要有一个执行成功就会返回,下边的都不会执行。 如果上述都没有找到或者一个都没执行成功,则进入Kernel Panic,如下所示: panic(“No init found. Try passing init= option to kernel. ”“See Linux Documentation/init.txt for guidance.”);
参考网址:linux启动分析——init进程与app启动
概述
内核init进程成功执行上边的一个init之后,内核init进程就转化为了用户空间的init进程。 一般情况下,执行的是/sbin/init。 /sbin/init读/etc/inittab文件并运行里边的项,/etc/inittab里边一般有“::sysinit:/etc/init.d/rcS”,这条语句会首先执行。
源码位置
busybox/init/init.c
# ls -l /sbin/init lrwxrwxrwx 1 root root 14 Aug 27 2019 /sbin/init -> ../bin/busybox
可见最终执行的是busybox。
busybox的配置项FEATURE_USE_INITTAB决定是否读取/etc/inittab文件,如果没有配置,则不读取,执行默认的操作。 默认情况下FEATURE_USE_INITTAB配置为y
/etc/init.d/rcS的一般套路
挂载proc,sysfs,ramfs文件系统 配置网络 启动app