我正在尝试为调用大量外部进程的大脚本实现超时。
我启动一个单独的进程作为看门狗,每秒检查是否达到超时
(
PARENT_PID=$$
((t = 2 ))
while ((t > 0)); do
sleep 1
((t -= 1))
done
kill -s ALRM ${PARENT_PID} 2> /dev/null
) &
然后我ALRM
在主脚本中捕获信号
trap critical ALRM
最后在关键函数中我打印出一些文本并干净地退出程序
现在问题来了
- 如果 $PARENT_PID 运行时发生超时,一切都会按预期工作
- 如果在子进程运行时发生超时(例如,我调用 openssl 并且 openssl 正在运行),则不会发生任何情况。如果我终止正在运行的子进程(例如按CRTL+ C),父进程陷阱将被激活,一切都会按预期继续
我该如何解决这个问题?这样父进程中的陷阱就会被调用并且我可以终止整个进程吗?
更新
如果看门狗杀死-KILL
父进程,则处理所有子进程的进程将按预期终止
问题是我想拦截超时并生成一些输出。为此,我使用 ALRM 信号。
信号KILL
不能被忽略,而信号可以被忽略ALRM
。
我目前的想法如下:
- 父进程有一个警报陷阱
- 子进程忽略警报信号
- 当信号发送到父进程时,子进程正在运行,父进程在后台
- 当孩子终止时我的进程被唤醒
如果这是正确的,我的想法将永远不会奏效。
为了使它工作,我应该为每个子进程
- 在后台启动它
- 等待并继续
这样父进程就能捕获信号
我对么?
更新2
一个简化的例子
critical() {
printf "whathever\n"
WATCHDOG_PID=$!
kill -TERM $WATCHDOG_PID
}
(
PARENT_PID=$$
((t = "${TIMEOUT}" ))
while ((t > 0)); do
sleep 1
((t -= 1))
done
kill -s ALRM ${PARENT_PID} 2> /dev/null
) &
trap critical ALRM
# an example of a long running command
(echo 'Q' | openssl s_client -connect corti.li:imap -servername corti.li -verify 6 ) &
wait
WATCHDOG_PID=$!
kill -TERM $WATCHDOG_PID
openssl
如果在运行时发送 ALRM 信号,则不会发生任何情况。即使openssl
在后台,陷阱也永远不会被调用
答案1
完整的答案需要您父母的代码,但如果缺乏,这里是可能发生的情况的提示:
开放组基本规范第 6 期 -第2.11节
当 shell 等待实用程序执行前台命令完成时接收到已设置陷阱的信号时,与该信号关联的陷阱只有在前台命令完成后才会执行。
当 shell 通过
wait
实用程序等待异步命令完成时,接收到已设置陷阱的信号应导致实用wait
程序立即返回,退出状态 >128,之后立即关联陷阱应采取该信号。
(格式化我的)
这意味着,如果您的父进程正在等待wait
命令以外的任何内容,则信号处理会被延迟,直到它正在执行的操作结束为止。
您可以让您的父母等待wait
,以便它可以立即收到您的 SIGALRM。