![关闭时向正在运行的程序/脚本发送什么信号?](https://linux22.com/image/147903/%E5%85%B3%E9%97%AD%E6%97%B6%E5%90%91%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E7%A8%8B%E5%BA%8F%2F%E8%84%9A%E6%9C%AC%E5%8F%91%E9%80%81%E4%BB%80%E4%B9%88%E4%BF%A1%E5%8F%B7%EF%BC%9F.png)
现在我有以下内容:
# this function is meant for future script expansions
# its purpose is clear, i.e. to clean up some temp files
# now, it is doing nothing, just a special null command
cleanup_on_signal() { :; }
# define functions to handle signals
# treat them as errors with appropriate messages
# example calls:
# kill -15 this_script_name # POSIX, all shells compatible
# kill -TERM this_script_name # Bash and alike - newer shells
signal_handler_HUP() { cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGHUP (1).\\n\\tClean-up finished.\\n\\tTerminating. Bye!"; }
signal_handler_INT() { cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGINT (2).\\n\\tClean-up finished.\\n\\tTerminating. Bye!"; }
signal_handler_QUIT() { cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGQUIT (3).\\n\\tClean-up finished.\\n\\tTerminating. Bye!"; }
signal_handler_ABRT() { cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGABRT (6).\\n\\tClean-up finished.\\n\\tTerminating. Bye!"; }
signal_handler_TERM() { cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGTERM (15).\\n\\tClean-up finished.\\n\\tTerminating. Bye!"; }
# use the above functions as signal handlers;
# note that the SIG* constants are undefined in POSIX,
# and numbers are to be used for the signals instead
trap 'signal_handler_HUP' 1; trap 'signal_handler_INT' 2; trap 'signal_handler_QUIT' 3; trap 'signal_handler_ABRT' 6; trap 'signal_handler_TERM' 15
我希望脚本在关闭时整齐地终止,现在确实如此。
但我听取了一位同事的建议,在 CTRL+C 上提出问题,而不是退出到 shell。
我不想关闭机器,反正我不经常这样做:
关闭时向正在运行的程序/脚本发送什么信号?
答案1
在关闭时,运行的进程首先被 init(来自旧实现上的 sendigs,根据 @JdeBP)/systemd 告知停止。
其余进程(如果有)将被发送 SIGTERM。那些忽略 SIGTERM 或未按时完成的进程,会在不久之后由 init/systemd 发送 SIGKILL。
这些措施旨在保证稳定/干净的关闭(尽可能)。
出于好奇,请参阅相关(旧)systemd
错误的报告:
Bug 1352264 - systemd 在关闭期间在 SIGTERM 之后立即发送 SIGKILL
systemd 在关闭期间在 SIGTERM 之后立即发送 SIGKILL,进程没有机会终止
同样来自shutdown.c
/main():
disable_coredumps(); log_info("Sending SIGTERM to remaining processes..."); broadcast_signal(SIGTERM, true, true, arg_timeout); log_info("Sending SIGKILL to remaining processes..."); broadcast_signal(SIGKILL, true, false, arg_timeout);
同样来自 sysvinit 2.94 sources/init.c,这是围绕 SIGTERM 轮的代码。如果任何进程被发送了 SIGTERM,则在 5 秒内每秒测试一次以查看是否还有任何进程剩余。如果在其中一个测试中没有找到任何进程,则停止等待,或者在 5 秒后向剩余进程发送 SIGKILL。
switch(round) {
case 0: /* Send TERM signal */
if (talk)
initlog(L_CO,
"Sending processes configured via /etc/inittab the TERM signal");
kill(-(ch->pid), SIGTERM);
foundOne = 1;
break;
case 1: /* Send KILL signal and collect status */
if (talk)
initlog(L_CO,
"Sending processes configured via /etc/inittab the KILL signal");
kill(-(ch->pid), SIGKILL);
break;
}
talk = 0;
}
/*
* See if we have to wait 5 seconds
*/
if (foundOne && round == 0) {
/*
* Yup, but check every second if we still have children.
*/
for(f = 0; f < sleep_time; f++) {
for(ch = family; ch; ch = ch->next) {
if (!(ch->flags & KILLME)) continue;
if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
break;
}
if (ch == NULL) {
/*
* No running children, skip SIGKILL
*/
round = 1;
foundOne = 0; /* Skip the sleep below. */
break;
}
do_sleep(1);
}
}
}
/*
* Now give all processes the chance to die and collect exit statuses.
*/
if (foundOne) do_sleep(1)
for(ch = family; ch; ch = ch->next)
if (ch->flags & KILLME) {
if (!(ch->flags & ZOMBIE))
initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
ch->id);
else {
INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
ch->pid, ch->id);
ch->flags &= ~RUNNING;
if (ch->process[0] != '+')
write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
}
}
/*
* Both rounds done; clean up the list.
*/