当前位置:网站首页>busybox之reboot命令流程分析
busybox之reboot命令流程分析
2022-07-31 11:52:00 【szembed】
busybox初始化注册reboot处理信号
busybox启动的时候,会注册reboot的处理信号
init_main
bb_signals(0
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGTERM) /* reboot */
+ (1 << SIGUSR2) /* poweroff */
, halt_reboot_pwoff);
signal(SIGQUIT, restart_handler); /* re-exec another init */
- 1
- 2
- 3
- 4
- 5
- 6
- 7
busybox 的命令对应入口查找流程
运行busybox对应的命令的时候,处理流程如下:
busybox对外提供了一个命令列表,支持非常多的命令
这个列表在代码里面的 include/applet_names.h
applet_names 定义了字符串和函数钩子的对应列表applet_main,顺序是一一对应的
入这里 reboot —> halt_main
其他命令的处理入口函数根据这个顺序去查找
lbb_main
run_applet_and_exit
int applet = find_applet_by_name(name);
if (applet >= 0)
run_applet_no_and_exit(applet, argv);
if (!strncmp(name, "busybox", 7))
exit(busybox_main(argv));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
从这段代码可以看出来,运行busybox命令的时候,会根据name查找到
命令在 applet_main 的下表索引 applet_no ,最后直接调用
applet_main[applet_no](argc, argv)命令执行对应命令的处理函数
reboot命令处理函数 halt_main
该函数的主要处理流程如下:
if (!(flags & 4)) { /* no -f */
//TODO: I tend to think that signalling linuxrc is wrong
// pity original author didn't comment on it...
if (ENABLE_FEATURE_INITRD) {
/* talk to linuxrc */
/* bbox init/linuxrc assumed */
pid_t *pidlist = find_pid_by_name("linuxrc");
if (pidlist[0] > 0)
rc = kill(pidlist[0], signals[which]);
if (ENABLE_FEATURE_CLEAN_UP)
free(pidlist);
}
if (rc) {
/* talk to init */
if (!ENABLE_FEATURE_CALL_TELINIT) {
/* bbox init assumed */
rc = kill(1, signals[which]);
} else {
/* SysV style init assumed */
/* runlevels:
* 0 == shutdown
* 6 == reboot */
rc = execlp(CONFIG_TELINIT_PATH,
CONFIG_TELINIT_PATH,
which == 2 ? "6" : "0",
(char *)NULL
);
}
}
} else {
rc = reboot(magic[which]);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
这里可以看出来,分为两个流程:
- 当reboot命令没有加 -f的时候,直接使用kill发送信号到busybox执行halt_reboot_pwoff函数
- 直接使用-f的话,直接使用reboot系统调用接口,通知内核,让内核执行重启操作,简单粗暴
halt_reboot_pwoff函数处理流程
我们大部分的重启命令都是直接使用reboot命令,最后走halt_reboot_pwoff流程,
当我们执行reboot的时候,一般都会有以下的打印:
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system reboot
- 1
- 2
- 3
- 4
从上面可以看出来,分为三步:
- 发送SIGTERM给所有进程,让进程正常退出
- 发送SIGKILL给所有进程,将其杀掉
- 让系统重启
以上三步都是在halt_reboot_pwoff里面实现的
static void halt_reboot_pwoff(int sig) { const char *m; unsigned rb;/* We may call run() and it unmasks signals, * including the one masked inside this signal handler. * Testcase which would start multiple reboot scripts: * while true; do reboot; done * Preventing it: */ reset_sighandlers_and_unblock_sigs(); run_shutdown_and_kill_processes(); m = "halt"; rb = RB_HALT_SYSTEM; if (sig == SIGTERM) { m = "reboot"; rb = RB_AUTOBOOT; } else if (sig == SIGUSR2) { m = "poweroff"; rb = RB_POWER_OFF; } message(L_CONSOLE, "Requesting system %s", m); pause_and_low_level_reboot(rb); /* not reached */
}
static void run_shutdown_and_kill_processes(void)
{
/* Run everything to be run at “shutdown”. This is done prior
* to killing everything, in case people wish to use scripts to
* shut things down gracefully… */
run_actions(SHUTDOWN);
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
/* Send signals to every process _except_ pid 1 */
kill(-1, SIGTERM);
message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
sync();
sleep(1);
kill(-1, SIGKILL);
message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
sync();
/*sleep(1); - callers take care about making a pause */
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
上面的源码可以看出来,halt_reboot_pwoff直接调用run_shutdown_and_kill_processes去
完成第一第二步,中间sleep 一秒钟
第三步是直接使用vfork子进程出来下发系统调用reboot(magic)命令给内核,让内核完成重启,
这一步和我们直接用reboot -f基本一致,也就是说reboot和reboot -f之间相差了第一第二步而已。
内核处理reboot系统调用流程
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)
kernel_restart(NULL);
kernel_restart_prepare(cmd);
migrate_to_reboot_cpu();
syscore_shutdown();
if (!cmd)
pr_emerg("Restarting system\n");
else
pr_emerg("Restarting system with command '%s'\n", cmd);
kmsg_dump(KMSG_DUMP_RESTART);
machine_restart(cmd);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
用户态运行reboot命令,除了用户态先kill所有用户态进程之外,还需要通过系统调用reboot接口
通知内核,让内核执行正常的cpu重启,这里涉及到不同架构cpu板子的重启,所以这里是分架构
来调用对应架构的重启cpu操作的.
边栏推荐
- [Virtualization ecological platform] Raspberry Pi installation virtualization platform operation process
- Initial JDBC programming
- Service discovery of kubernetes
- IDEA configure method annotation automatic parameters
- PyQt5快速开发与实战 9.5 PyQtGraph在PyQt中的应用 && 9.6 Plotly在PyQt中的应用
- 3.网页信息解析方法:Xpath与BeautifulSoup
- Docker安装canal、mysql进行简单测试与实现redis和mysql缓存一致性
- R 语言data.frame 中的另一行中减去一行
- JVS轻应用的组成与配置
- Curl 命令使用
猜你喜欢

Android studio connects to MySQL and completes simple login and registration functions

Read through the interface to call the artifact RestTemplate

准确率(Accuracy)、精度(Precision)、召回率(Recall)和 mAP 的图解

Mysql环境变量的配置(详细图解)

矩形脉冲波形的占空比及脉冲和瞬态特征的测量

ApiPost is really fragrant and powerful, it's time to throw away Postman and Swagger

WebGL给Unity传递参数问题1: Cannot read properties of undefined (reading ‘SendMessage‘)

3.网页信息解析方法:Xpath与BeautifulSoup

MySQL row-level locks (row locks, adjacent key locks, gap locks)

The latest MySql installation teaching, very detailed
随机推荐
MySQL index usage and optimization
Data Persistence Technology - MP
ESP8266-Arduino编程实例-MCP9808数字温度传感器驱动
下课看着文档走回实验室,我重新拾起了遗忘的SQL运算符
【软件工程之美 - 专栏笔记】33 | 测试工具:为什么不应该通过QQ/微信/邮件报Bug?
JVS开发套件产品定位
Redis - Basics
JVS函数公式使用场景介绍
CWE4.8 -- 2022年危害最大的25种软件安全问题
如何正确地把服务器端返回的文件二进制流写入到本地保存成文件
连续变量离散化教程
Android studio连接MySQL并完成简单的登录注册功能
安装MYSQL遇到问题:write configuration file卡主
使用 Excel 读取 SAP ABAP CDS View 通过 ODBC 暴露出来的数据
IDEA 配置方法注释自动参数
MySQL日志中“binlog”的三种格式玩起来真爽
[Virtualization Ecological Platform] Platform Architecture Diagram & Ideas and Implementation Details
JVS低代码能力简介及功能清单
关于Mysql数据库的介绍
蓝牙协议栈开发板 STM32F1 跑蓝牙协议栈 –传统蓝牙搜索演示以及实现原理[通俗易懂]
