当前位置:网站首页>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操作的.
边栏推荐
- 5 个开源的 Rust Web 开发框架,你选择哪个?
- mysql 索引使用与优化
- Docker practical experience: Deploy mysql8 master-slave replication on Docker
- SAP Commerce Cloud Product Review 的添加逻辑
- 学自动化测试哪个培训机构好 试听课程后就选了这个地方学习
- 最新MySql安装教学,非常详细
- 5 open source Rust web development frameworks, which one do you choose?
- 无法将“node.exe”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
- MySQL limit paging query and performance issues
- 科学论文和学术论文写作
猜你喜欢

Data Persistence Technology - MP

文件包含漏洞

瑞吉外卖项目:新增菜品与菜品分页查询

Chrome开发自定义右键菜单实现快速跳转到指定页面

If the value of the enum map does not exist, deserialization is not performed

Redis学习笔记-3.慢查询和其他高级数据结构

vb.net 画曲线

The item 'node.exe' was not recognized as the name of a cmdlet, function, script file, or runnable program.

分布式事务——分布式事务简介、分布式事务框架 Seata(AT模式、Tcc模式、Tcc Vs AT)、分布式事务—MQ
502 bad gateway原因、解决方法
随机推荐
三六零与公安部三所发布报告:关基设施保护成为网络安全博弈关键
关于Mysql数据库的介绍
【软件工程之美 - 专栏笔记】33 | 测试工具:为什么不应该通过QQ/微信/邮件报Bug?
学习笔记 Golang 写入文件(io.WriteString、ioutil.WriteFile、file.Write、write.WriteString)
DCM middleware family welcomes a new member
After class, watching the documentation and walking back to the lab, I picked up the forgotten SQL operators again
mysql automatically adds creation time and update time
MySQL index usage and optimization
Detailed tutorial on distributed transaction Seata
关于IDEA开发工具的介绍
音视频基础
多线程学习笔记-2.final关键字和不变性
分布式事务Seata详细使用教程
Yarn安装配置(vsftpd安装配置)
strings包详细文档+示例
Docker安装canal、mysql进行简单测试与实现redis和mysql缓存一致性
Curl 命令使用
Chrome开发自定义右键菜单实现快速跳转到指定页面
如何正确地把服务器端返回的文件二进制流写入到本地保存成文件
[Virtualization ecological platform] Raspberry Pi installation virtualization platform operation process
