这是关于在POSIX(Linux)环境中运行的应用程序。处理大多数信号(例如 Ctrl + C - 信号2,SIGINT)和其他几个信号。完成后,将从处理程序调用{{1}}系统调用,并使用所需的退出代码。
但是,有些信号如Signal 9和Signal 15无法处理。
不幸的是,如果信号9或15是终止的原因,启动给定应用程序的父进程(外部脚本)需要知道并清理一些东西。
是否有父进程可以接收的预定义退出代码以了解上述内容?
启动应用程序的脚本是bash_script。应用程序本身位于C.
答案 0 :(得分:5)
wait()
或waitpid()
的返回状态会对您需要的信息进行编码。
POSIX宏是:
WIFEXITED(status)
或其中一位亲属退出,则exit()
会返回true。WEXITSTATUS(status)
告诉您退出状态是什么(0..255)。WIFSIGNALED(status)
返回true。WTERMSIG(status)
返回杀死孩子的信号编号。非标准但通用的宏WCOREDUMP(status)
会告诉您进程是否转储了核心。您还可以判断状态是否反映了流程已停止或继续(以及停止信号是什么)。
请注意,信号15通常是SIGTERM,SIGTERM可以被应用程序捕获。无法捕获的信号是SIGKILL(9)和SIGSTOP(Mac OS X上的17;在任何地方可能都不一样)。
问题是,如果
bash
为脚本提供此信息。
答案是肯定的,但只是间接而非100%明确无误。对于因信号bash
而终止的流程,128 + <signum>
报告的状态值为<signum>
,但您无法区分退出状态为130
的流程,例如,以及被SIGINT中断的进程,即信号2。
答案 1 :(得分:2)
15(SIGTERM
)可以被应用程序捕获和处理,如果它选择这样做,但也许它现在不是
9(SIGKILL
)显然无法被任何应用程序捕获。
然而,通常操作系统以这样的方式设置退出状态,即可以识别终止该过程的信号。通常只有exit(3)函数[和_exit(2)系统调用]的status参数的低8位被复制到wait(2)返回到父进程的status
值( shell在您的示例中运行外部脚本)。因此,在sizeof(int)-1
值中留下status
个字节的空间,以供操作系统用于填写有关已终止进程的其他信息。通常,wait(2)手册页将描述解释等待状态的方法,从而将进程终止的任何其他信息从进程传递给_exit(2),IFF流程退出。
不幸的是,这些额外信息是否可用于脚本取决于执行脚本的shell如何处理它。
首先查看您的shell手册页,详细了解如何解释$?
。
如果shell使整个status
int
值逐字地提供给脚本(在$?
变量中),那么就可以解析该值并确定如何和程序退出的原因。大多数shell似乎并没有完全做到这一点(并且对于各种规定,其中最重要的可能是标准兼容性),但它们至少足以使解决您的查询成为可能(并且必须是POSIX兼容)。
例如,我在Mac OS X上运行AT&amp; T版本的KSH。我的ksh(1)手册页说如果程序刚刚正常运行,则退出状态为0-255(其中值为大概是传递给_exit(2)的内容和256 + signum,如果过程被信号终止(编号为“signum”)。我不知道在Linux上,但在OS X上bash提供了与Ksh不同的退出状态(使用bash使用第8位表示信号,因此仅允许0-127作为有效退出值)。 (在wait(2)声称_exit(2)的8个低位可用,以及shell将等待状态转换为$?
而仅保留7位之间,POSIX标准存在差异。 !Ksh的行为违反了POSIX,但它更安全,因为严格兼容的shell可能无法区分将值128-255传递给_exit(2)并且已被信号终止的进程。)< / p>
所以,无论如何,我开始cat
进程,然后我从终端发送SIGQUIT
(按^)(我使用SIGQUIT
因为没有简单的发送方式来自终端键盘的SIGTERM
:
22:01 [2389] $ cat
^\Quit(coredump)
ksh: exit code: 259
(我有一个shell EXIT
陷阱被定义为打印$?如果它不是零,所以你也看到它上面了)
22:01 [2390] $ echo $?
259
(259是一个整数值,表示wait(2)返回shell的状态)
22:02 [2391] $ bc
obase=16
259
103
^D22:03 [2392] $
(参见259的十六进制值为0x0103,注意0x0100为十进制256)
22:03 [2392] $ signo SIGQUIT
#define SIGQUIT 3 /* quit */
(我有一个名为signo
的shell别名,它搜索标题以找到代表符号信号名称的数字。请参见此处,状态值中的0x03与SIGQUIT
的数字相同。)
进一步探索wait(2)系统调用以及来自<sys/wait.h>
的相关宏将使我们能够更多地了解正在发生的事情。
在C中,解码等待状态的基本逻辑使用来自<sys/wait.h>
的宏:
if (!WIFEXITED(status)) {
if (WIFSIGNALED(status)) {
termsig = WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
stopsig = WSTOPSIG(status);
}
} else {
exit_value = WEXITSTATUS(status));
}
我希望有所帮助!
答案 2 :(得分:0)
如果SIGNAL发生在用户空间之外,父进程无法检测到SIGKILL或Signal 9。
建议让您的父进程检测您的子进程是否已经消失并相应地处理它。在mysqld-safe等中可以看到一个很好的例子。