2

这是关于在 POSIX (Linux) 环境中运行的应用程序。大多数信号(例如Ctrl+ C- 信号 2、SIGINT)和少数其他信号都被处理。完成后,exit()系统调用会从处理程序中调用,并带有所需的退出代码。

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

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

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

启动应用程序的脚本是 bash_script。应用程序本身是 C 语言。

4

3 回答 3

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% 明确的。报告的状态值bash128 + <signum>针对因信号而终止的进程<signum>,但您无法区分以状态退出130的进程和被 SIGINT 中断的进程,即信号 2。

于 2012-11-16T05:11:02.757 回答
2

15 ( SIGTERM) 可以被应用程序捕获和处理,如果它选择这样做的话,但目前可能没有

9 ( SIGKILL) 显然不能被任何应用程序捕获。

但是,通常操作系统设置退出状态的方式是可以识别终止进程的信号。通常只有 exit(3) 函数的状态参数的低 8 位 [以及 _exit(2) 系统调用] 被复制到statuswait(2) 返回给父进程(运行外部脚本的 shell)的值中在你的例子中)。因此,这会在值中留下sizeof(int)-1字节空间status供操作系统用于填充有关已终止进程的其他信息。通常,wait(2) 手册页将描述解释等待状态的方式,从而将有关进程终止的任何附加信息与进程传递给 _exit(2) 的状态分开,IFF 进程退出。

不幸的是,脚本是否可以使用这些额外信息取决于执行脚本的 shell 如何处理它。

首先查看 shell 的手册页,了解如何解释$?.

如果 shell 将整个status int值逐字提供给脚本(在$?变量中),则可以解析该值并确定程序退出的方式和原因。大多数 shell 似乎并没有完全做到这一点(出于各种原因,其中最重要的可能是标准合规性),但它们至少做得足够远,可以解决您的查询(并且必须是 POSIX兼容的)。

例如,我在 Mac OS X 上运行 AT&T 版本的 KSH。我的 ksh(1) 手册页说,如果程序正常运行终止,则退出状态为 0-255(其中的值大概是传递给_exit(2)) 和 256+signum 如果进程被信号终止(编号为“signum”)。我不知道在 Linux 上,但在 OS X 上,bash 给出的退出状态与 Ksh 不同(bash 使用第 8 位来表示信号,因此只允许 0-127 作为有效的退出值)。(在 POSIX 标准中,wait(2) 声称 _exit(2) 的 8 个低位可用,而 shell 将等待状态转换为$?仅保留 7 位。去搞清楚!Ksh 的行为违反了 POSIX,但它更安全,因为严格兼容的 shell 可能无法区分将值 128-255 传递给 _exit(2) 和已被信号终止的进程。)

所以,无论如何,我开始一个cat进程,然后我从终端发送它SIGQUIT(通过按 ^)(我使用SIGQUIT是因为没有简单的方法SIGTERM从终端键盘发送):

22:01 [2389] $ cat
^\Quit(coredump)
ksh: exit code: 259

(我EXIT定义了一个 shell 陷阱来打印 $? 如果它不为零,那么您也可以在上面看到它)

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 */

(我有一个名为的 shell 别名signo,用于搜索标头以查找表示符号信号名称的数字。请参见此处,状态值中的 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));
}

我希望这会有所帮助!

于 2012-11-16T06:07:13.730 回答
0

父进程不可能检测到 SIGKILL 或 Signal 9 - 因为 SIGNAL 发生在用户空间之外。

一个建议是让您的父进程检测您的子进程是否已经消失并相应地处理它。在 mysqld-safe 等中可以看到一个很好的例子。

于 2012-11-16T05:06:09.557 回答