返回无法处理的POSIX信号的代码

时间:2012-11-16 04:50:49

标签: c linux signals exit-code

这是关于在POSIX(Linux)环境中运行的应用程序。处理大多数信号(例如 Ctrl + C - 信号2,SIGINT)和其他几个信号。完成后,将从处理程序调用{​​{1}}系统调用,并使用所需的退出代码。

但是,有些信号如Signal 9和Signal 15无法处理。

不幸的是,如果信号9或15是终止的原因,启动给定应用程序的父进程(外部脚本)需要知道并清理一些东西。

是否有父进程可以接收的预定义退出代码以了解上述内容?

启动应用程序的脚本是bash_script。应用程序本身位于C.

3 个答案:

答案 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等中可以看到一个很好的例子。