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 */
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));
从这段代码可以看出来,运行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]);
}
这里可以看出来,分为两个流程:
- 当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
从上面可以看出来,分为三步:
- 发送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 */
}
上面的源码可以看出来,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);
用户态运行reboot命令,除了用户态先kill所有用户态进程之外,还需要通过系统调用reboot接口
通知内核,让内核执行正常的cpu重启,这里涉及到不同架构cpu板子的重启,所以这里是分架构
来调用对应架构的重启cpu操作的.