干货分享!Linux内核线程之创建0号进程与1号进程

进程#0是Linux内核中的内核线程。
它的名字是空闲进程。
它是Linux操作系统初始化阶段的第一个内核线程。
进程#0有两个主要功能:一是创建进程#1,二是在没有进程就绪时执行cpu_idle函数,使CPU保持在空闲状态。
在Linux中,存在三个特殊进程:idle进程(PID=0)、init进程(PID=1)和kthreadd(PID=2)。
空闲进程是系统自动创建的,运行在内核态。
创建进程0的整个过程涉及到内核初始化后通过alloc_proc函数获取进程控制块实例。
在初始化过程中,分配一个与进程控制块结构大小相同的指针变量,并初始化其中的字段。
然后将值分配给进程控制块变量,其中包括内核堆栈设置、状态、进程号、need_resched和进程名称。
其他非指定字段如mm、tf、context、parent等都有各自特定的用途和含义。
mm用于虚拟内存管理,但内核线程在内存中,所以不需要考虑交换页问题。
上下文用于进程切换,所有进程在内核中都是相对独立的。
tf用于记录中断帧信息。
进程#0是内核线程,不需要存储中断信息。
Parent表示进程0没有父进程。
进程#1也是一个内核线程,通常称为init进程。
它的主要功能是完成内核初始化并调用Execve系统调用来执行Init可执行程序。
init进程是在空闲时通过kernel_thread创建的。
内核空间初始化完成后,加载init程序,最终在用户空间执行。
进程#0创建Init进程来完成系统的初始化。
所有的Linux进程都是由init进程创建和执行的。
init进程在系统启动完成后成为守护进程,监视系统中其他进程的活动。
创建进程#1的过程涉及使用kernel_thread函数创建一个实例化中断帧tf并填充关键信息的进程。
分配进程控制块实例,设置父进程为当前值,分配内核堆栈并转换为虚拟地址,设置进程号PID等。
设置中断帧和上下文集,分配堆栈空间并复制初始值,设置esp和eflags,并将eflags设置为FL_IF标志以指示进程可以响应中断。
堆栈指针指向中断帧,IP指向Forkret。
执行完毕后,当前进程切换到新进程,并加载寄存器值,完成环境布局。
Process#0和Process#1的创建过程的主要区别在于Process#0是“前所未有的”,在创建时没有当前变量。
它在创建后可以成为当前变量。
进程#1创建后,将其添加到进程控制块的双向链表中,以供调度程序进行调度。
后续文章将详细介绍Process#1的规划过程。

Linux下的init0,1,2,3,4,5,6知识介绍

init进程在Linux系统中起着重要的作用。
作为内核启动后的第一个用户级进程,它指导整个系统初始化过程。
通常,init进程的正确位置是/sbin/init。
如果没有找到,系统将尝试从/bin/sh启动。
否则,启动会失败。
init进程分为七个级别,每个级别代表一种不同的系统运行模式。
-Level0:关机或关机。
不要将其设置为默认值。
-级别1:单用户模式。
仅适用于root权限。
-级别2:多用户模式。
不支持NFS。
-级别3:标准多用户模式或完全多用户模式,启用NFS服务。
-4级:安全模式。
用于系统维护。
-Level5:图形界面模式。
-Level6:也不将重启设置为默认值。
每个级别的执行状态由位于/etc/rc.d/的rc*.d文件中的脚本控制。
例如,init0对应运行halt和killall命令,表示init1启动的程序包含单用户模式服务。
观察这些目录中的文件可以更直观地了解每个级别的功能差异。
不同版本的Linux系统的文件结构可能略有不同,都是通过软链接实现的。
如果您想了解更多Linux技术,请关注我们的公众号【Linux架构师训练营】。