busybox之内核线程init

前提:

        linux内核启动运行到run_init_process("sbin/init")

为什么入口是init_main?

执行/sbin/init进程的时候,会执行lbbmain()或者main(),这两个是根据宏定义来命名的。调用run_applet_no_and_exit从函数数组applet_main中查找init_main来调用,相应的,如果是别的指令比如说ls就调用ls_main

另外init本身也可以调用lbbmain()或者main()来执行新的进程(作业)

init_main:

首先初始化全局变量和信号掩码

(如果定义了调试模式,就初始化调试处理器)

检查PID是否为1

设置die_fun为sleep_much(这个函数是睡眠30天)

初始化控制台和设置环境变量

打印欢迎信息

检查是否为单用户模式,分情况调用new_init_action

不是单用户模式时通过parse_inittab调用多个new-init_action

#if ENABLE_SELINUX

{  加载SELinux策略

 ...  }

  #if ENABLE_FEATURE_INIT_MODIFY_CMDLINE

修改命令行,让ps仅显示init不显示其他初始化进程

设置SIGSTOP和SIGTSTP信号处理函数

执行初始化命令:调用多个run_actions()

循环执行动作

while(1){

重新运行respawn/askfirst命令

等待任何信号(通常是SIGCHLD)

等待任何子进程退出

sleep(1);

//初始化完成后init就留在这个死循环里面,init不会终止,当产生孤儿进程时,init会作为孤儿进程的父进程。

}

parse_inittab:

打开inittab,进行相应配置(etc文件夹里全是配置文件)

/etc/inittab 主要用于系统启动时定义各种初始化任务、控制台设置、重启行为等。在 inittab 文件中,每一行定义了一个任务或操作。

从输出信息可以看到调用了5个new_init_action

run_actions:

根据不同的状态分情况调用run函数,其中有(SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN)这三种状态任意个的需要显式等待子进程的完成

run:

shell里每个创建的进程都是一个新的作业,需要重设信号集和进程组。

open_stdio_to_tty:

这个函数就是把标准输入输出重定位到新建的进程

显然,只有新的进程是一个终端时,才能样做

这个函数通过判断tty_name是否为空决定是否重定位,不空就重定位

一些注意

设置die_func为sleep_much的目的

防止init进程退出: init进程是系统中的第一个进程(PID 1),负责系统的初始化和管理所有其他进程。如果init进程退出,系统将会进入一种不可恢复的状态,通常会导致系统崩溃。因此,防止init进程退出是至关重要的。

防止内核恐慌: 如果init进程退出,系统可能会发生内核恐慌(kernel panic),这是内核检测到不可恢复的错误时采取的保护机制。通过让init进程进入长时间的休眠,可以避免内核恐慌的发生。

给予管理员时间进行干预: 长时间的休眠提供了一个缓冲期,允许系统管理员在检测到问题后有时间进行干预和修复,而不是立即面对系统崩溃。

系统恢复的最后手段: 在某些情况下,即使init进程遇到了致命错误,它仍然可以通过进入休眠状态来保持系统的基本稳定性,这样即使不能立即解决问题,系统也不会立即崩溃。

用户进程和内核线程

·  用户进程是在用户空间中运行的独立实体,具有自己的虚拟地址空间和资源,主要用于用户应用程序的执行。

·  内核线程是在内核空间中运行的线程,用于处理系统级任务,它们共享内核地址空间和资源,通常用于支持内核的操作和任务

输出信息

VFS: Mounted root (ext3 filesystem) readonly on device 179:0.

Freeing unused kernel memory: 1024K

lsj -- run_init_process is called. init_filename:/sbin/init

Run /sbin/init as init process

lsj -- kernel_execve is called. filename is : /sbin/init

random: crng init done

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is /sbin/init

lsj -- parse_init is called.

lsj -- new_init_action is called. command is /etc/init.d/rcS  tty is

lsj -- new_init_action is called. command is -/bin/sh  tty is /dev/console

lsj -- new_init_action is called. command is /sbin/reboot  tty is

lsj -- new_init_action is called. command is /bin/umount -a -r  tty is

lsj -- new_init_action is called. command is /sbin/init  tty is

| lsj -- init_main calls run_actions(SYSINIT)

|||  lsj -- run is called.

||| lsj -- open_stdio_to_tty is called.  tty_name is

||| lsj -- wait for pid: []

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is /bin/sh

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is mount

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is mkdir

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is mount

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is mdev

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is mkdir

mkdir: can't create directory '/var/lock': Read-only file system

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is ifconfig

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is /bin/hostname

| lsj -- init_main calls run_actions(WAIT)

| lsj -- init_main calls run_actions(ONCE)

| lsj -- in while(1): init_main calls run_actions(ONCE)

|||  lsj -- run is called.

||| lsj -- open_stdio_to_tty is called.  tty_name is /dev/console

Please press Enter to activate this console.

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is -/bin/sh

[root@lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is /bin/hostname

vexpress ]# ls

lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is ls

bin         lib         mnt         sbin        usr

dev         linuxrc     proc        sys         var

etc         lost+found  root        tmp

[root@lsj -- lbb_main or main is called.

lsj -- run_applet_no_and_exit is called.  argv[0] is /bin/hostname

vexpress ]#

BusyBox 能够生成 `init` 进程,是因为它实现了 **一个精简版的 `init` 程序**,并可以在嵌入式 Linux 系统启动时作为第一个用户空间进程(即 PID 1)运行。 ### 一、Linux 启动流程中的 init 角色 在 Linux 系统中: 1. 内核启动后,会挂载根文件系统。 2. 然后内核尝试运行第一个用户空间程序:`/sbin/init`。 3. 这个程序就是所谓的“init 进程”,它是所有其他用户进程的祖先(PID = 1)。 4. 如果 `/sbin/init` 找不到,内核会依次尝试 `/etc/init`、`/bin/init`、`/bin/sh`。 > BusyBox 提供了这个关键的 `/sbin/init` 程序。 --- ### 二、BusyBox 如何实现 init BusyBox 将多个 Unix 工具编译成一个可执行文件(通常叫 `busybox`),并通过符号链接或硬链接来区分不同命令。例如: ```bash ln -s busybox ls ln -s busybox cp ln -s busybox init ``` 当系统调用 `/sbin/init` 时,实际上执行的是 BusyBox 可执行文件,但它会检测自己是通过哪个名字被调用的,并执行对应的功能 —— 这就是所谓的“多合一”设计。 所以,只要将 `busybox` 编译并链接为 `/sbin/init`,它就能作为 init 进程运行。 --- ### 三、BusyBox init 的工作流程 BusyBox 的 `init` 模块主要完成以下任务: 1. **解析 `/etc/inittab` 文件**(如果存在) - 定义系统启动时运行哪些脚本 - 配置终端登录(如串口控制台) ```text ::sysinit:/etc/init.d/rcS ::respawn:/sbin/getty 115200 tty1 ::askfirst:/bin/sh ``` 2. **执行系统初始化脚本** - 通常是 `/etc/init.d/rcS`,用于设置网络、挂载文件系统、启动服务等。 3. **启动终端登录进程(getty + login)** - 允许用户登录系统。 4. **进入运行循环,监控子进程(类似守护进程)** --- ### 四、如何让 BusyBox 生成 init 进程? #### 步骤示例: 1. **配置 BusyBox 包含 init 功能** ```bash make menuconfig # 勾选 Settings ---> Init Utilities ``` 2. **编译并安装 BusyBox** ```bash make && make CONFIG_PREFIX=/path/to/rootfs install ``` 安装后会在 `rootfs/sbin/init` 创建指向 `busybox` 的链接。 3. **确保 /sbin/init 存在且可执行** ```bash cd /path/to/rootfs ln -sf busybox init ``` 4. **可选:编写 /etc/inittab 控制行为** 若不提供 inittab,BusyBox 使用默认行为: - 执行 `/etc/init.d/rcS` - 在控制台启动 `/bin/sh` --- ### 五、总结 | 项目 | 说明 | |------|------| | **谁提供 init?** | BusyBox 编译出的 `init` 功能模块 | | **怎么运行?** | 内核启动后执行 `/sbin/init` → 实际是 BusyBox | | **做了什么?** | 初始化系统、运行脚本、启动 shell 或 getty | | **是否必须?** | 不是必须,但绝大多数嵌入式系统依赖它 | 你可以认为:**BusyBox 是最小化 Linux 系统的“操作系统基础工具包”,而它的 `init` 是整个用户空间的起点。**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值