【发布时间】:2018-11-20 19:08:21
【问题描述】:
我正在尝试编写一个信号处理程序,它需要知道发送信号的进程的 pid。我在使用 Xcode 10 的 macOS 10.14 上从 siginfo_t 传递到我的处理程序中的任何有用的东西都没有运气。
我已将我的代码简化为以下最小示例来演示该问题。在这个示例中,我生成了一个子进程来发送我想要测试的信号,该信号默认为SIGTERM,但我尝试过的其他信号都没有更好的效果。
假设您想在 Mac 上构建和测试它,您可能想告诉 lldb 在收到信号时不要停止。你可以使用这个 lldb 命令:pro hand -p true -s false SIGTERM。
我也在用 C++ 编译,但我相信我已经删除了所有这些,示例代码现在应该是纯 C。
请注意,无论信号来自子进程、终端还是其他进程,结果始终是 si_pid 始终为 0(以及除 si_signo 和 @987654329 之外的所有内容) @)。我发送信号多少次都没有关系,所以它似乎不仅仅是一个竞争条件。
如何获取在 macOS 10.14 上发送信号的进程的 pid?我不记得在 10.12 上遇到过这个问题,这是我之前使用的。
这只是一个演示问题的示例,因此请忽略任何实际上不会导致问题的内容。
如果代码看起来应该像我预期的那样工作,那么我有兴趣查看有关它也可以工作的系统的 cmets。
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
while (kill(mainpid, 0) == 0) {
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
}
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
while (1) {
if (signaled) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
}
sleep(1);
}
}
【问题讨论】:
-
需要添加
#include <stdbool.h>才能编译为C,顺便说一句。 -
@Shawn 谢谢,我已经编辑了代码。
-
信号处理程序还根据 POSIX 调用未定义的行为,因为它分配给不是
volatile sig_atomic_t的变量。 (Reference)。我可以通过积极的优化设置将 main 中的循环描绘成总是将signaled视为错误(但不能在 linux 上使用 gcc 或 clang 复制)。不过,没有用于实际有用测试的 mac。 -
@Shawn 我很感激,但是我的 IRL 代码没有。我将看到有关使用兼容代码更新示例的信息,但我不明白这可能是什么问题。调试器也总是说它是 0。
-
我很确定
struct sigaction sigAction = {};是无效的 C 代码。事实上,cppreference.com states“在 C 中,初始化器的大括号列表不能为空。”,但我不会解析 6.7.9 Initialization of the C standard 并验证它是否正确。