具有“SA_SIGINFO”的 macOS“sigaction()”处理程序不包含“si_pid”

2024-01-11

我正在尝试编写一个信号处理程序,它需要知道发送信号的进程的 pid。我没有运气从那里得到任何有用的东西siginfo_t使用 Xcode 10 传递到 macOS 10.14 上的处理程序。

我已将代码减少到以下最小示例来演示该问题。在此示例中,我生成一个子进程来发送我想要测试的信号,默认为SIGTERM,但我尝试过的其他信号都没有更好的效果。

假设您想在 Mac 上构建并测试它,您可能想告诉 lldb 在收到信号时不要停止。您可以使用以下 lldb 命令:pro hand -p true -s false SIGTERM.

我也在用 C++ 进行编译,但我相信我已经删除了所有这些,并且示例代码现在应该是纯 C 的。

请注意,信号是否源自子进程、终端或其他进程并不重要,结果始终是si_pid始终为 0(以及除si_signo and si_addr)。我发送信号多少次并不重要,所以这似乎不仅仅是一个竞争条件。

如何获取 macOS 10.14 上发送信号的进程的 pid?我不记得在我之前使用的 10.12 上有过这个问题。

这只是演示问题的示例,因此请忽略任何实际上不会导致问题的内容。

如果代码看起来应该按我的预期工作,那么我有兴趣查看有关它也可以工作的系统的评论。

#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);
    }
}

我目前使用的是 macOS Mojave 10.14.1。

如何获取 macOS 上发送信号的进程的 pid 10.14?我不记得在我之前使用的 10.12 上有过这个问题。

下面的代码简单地满足了您的愿望。如果您发送SIGTERM,你可以看到发送进程的pid。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

static void hdl (int sig, siginfo_t *siginfo, void *context)
{
    printf ("Sending PID: %ld, UID: %ld\n",
            (long)siginfo->si_pid, (long)siginfo->si_uid);
}

int main (int argc, char *argv[])
{
    struct sigaction act;

    fprintf(stderr, "%i pp %i\n",getpid(), getppid());

    memset (&act, '\0', sizeof(act));

    /* Use the sa_sigaction field because the handles has two additional parameters */
    act.sa_sigaction = &hdl;

    /* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
    act.sa_flags = SA_SIGINFO;

    if (sigaction(SIGTERM, &act, NULL) < 0) {
        perror ("sigaction");
        return 1;
    }

    while (1)
        sleep (10);

    return 0;
}

对于你的代码,

经验法则:即使您确定子进程结束了先前的父进程,也不要忘记执行埋葬程序。通过调用wait(...)你告诉操作系统我已经为我的孩子完成了我的事情,所以现在你可以清理分配的字段等。

我更喜欢在分叉之前初始化信号实用程序,如果父进程没有机会注册信号操作怎么办?此外,我不明白你为什么要处理0 and 1案件在switch。本质上,这些案例不会被击中,因此总是被忽略。

另外,你没有使用break在你的if内的条件main()。它进不去if过了一段时间,以下情况是不可预见和不可取的,即该程序永远停留在while()环形。我更愿意把signaled进入状态while() loop.

最后但并非最不重要的一点是,由于sleep()调用子进程直到signaled结果是0, SIGTERM多次被成功抓获。当发出信号时0,循环停止。

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <memory.h>
#include <sys/wait.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:
        fprintf(stderr, "sender pid -> %i\n", info->si_pid);
        histogram[2]++;
        break;
    }
    signaled = 1;
}

int main(int argc, const char * argv[]) {


    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);

    pid_t mainpid = getpid();
    pid_t pid = fork();
    if (pid == 0) {
        fprintf(stderr, "my pid -> %i parent's pid-> %i\n", getpid(), getppid());
        if (kill(mainpid, 0) == 0) { // signals are not queued not need loop
            sleep(1);
            kill(mainpid, testsig);
        }
        _exit(0);
    } else {

        wait(NULL); // play with this line to see what the difference is
        while ( signaled ) {
            printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
            signaled = 0;
            sleep(1);
        }
        // wait(NULL); // play with this line to see what the difference is

    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有“SA_SIGINFO”的 macOS“sigaction()”处理程序不包含“si_pid” 的相关文章

随机推荐

  • 信号处理程序不会看到全局变量

    问题是 这个程序应该接收来自 stdin 的输入并计算插入的字节数 SIGUSR1 信号将停止主程序 并在文件标准错误上打印当我发送 SIGUSR1 时已复制了多少字节 这就是我的老师希望我这样做的方式 在一个终端运行中 cat dev z
  • 为什么在使用 Javassist 更改方法体后必须调用 .toClass()?

    我修改getMessage 我的方法体TestClass由Javassist这样写 ClassPool cp new ClassPool true CtClass ctClass cp get my test javassist TestC
  • CSS:使 iframe 充满高度,没有滚动条

    我怎样才能在 iframe 上拥有完整的高度 这样如果超过指定的高度 我就没有滚动条height 500px 我只想让页面滚动条存在 而不是 iframe 滚动条 我知道你可以隐藏滚动条 但这样你就看不到 iframe 中的所有内容 你怎么
  • Sparklyr 与 S3 存储桶的连接抛出错误

    我正在尝试从 R Sparklyr 连接到 S3 存储桶 我能够将本地文件读取到 Spark 上下文中 然而尝试连接 s3 似乎是个问题 抛出一大堆错误 这是所使用的代码列表 注意 单个 s3 存储桶有多个 csv 文件 遵循相同的模式 l
  • 如何将 C 联合转换为 Delphi?

    typedef struct FILE OBJECTID INFORMATION LONGLONG FileReference UCHAR ObjectId 16 union struct UCHAR BirthVolumeId 16 UC
  • 如何在 Flutter 中使用 fl_chart 在折线图中水平滚动?

    我想用折线图显示列表中的数据 问题是宽度太小 所以我希望你可以水平滚动来查看所有内容 如何使用 fl chart 包执行此操作 这是我的代码 我从列表中构建点 override Widget build BuildContext conte
  • 使用php获取字符串中的第一个图像

    我正在尝试从我的每篇文章中获取第一张图片 如果我只有一张图像 下面的代码效果很好 但如果我有多个 它会给我一个图像 但并不总是第一个 我真的只想要第一张图片 很多时候第二张图片是下一个按钮 texthtml Who is Sara Bare
  • 根据 R 中的名称向量删除列

    我有一个data frame called DATA Using BASE R 我想知道如何删除中的任何变量DATA被命名为以下任意一个 ar c out Name mdif stder mpre 目前 我使用DATA names DATA
  • 如何自定义 jquery 自动完成以在 DIV 中显示

    我只是想知道 我以前使用过自动完成插件 但 jquery 网站上的示例似乎非常简单且有用 function var availableTags ActionScript AppleScript Asp BASIC C C Clojure C
  • CSS 参数“如果第一个孩子是”

    我需要一个用于 div 内部的 CSS 选择器 但我希望它仅选择该 div 内特定类的第一个元素 正如您的标题所暗示的 如果第一个孩子是 div gt test first child将选择任何的第一个孩子 div if它有类test 但如
  • 如何将事件记录到 ASP.NET Core Web API 中的事件查看器?

    我正在尝试登录到托管在 Windows Server 2016 Standard 上的 ASP NET Core 2 1 Web API 中的事件查看器 我的控制器中有这个 private readonly ILogger
  • azure服务结构可靠字典linq查询非常慢

    我在服务结构有状态服务中有一本可靠的字典 我有一个简单的 linq 表达式 我正在使用 Ix Async 包来构建异步枚举 using ITransaction tx this StateManager CreateTransaction
  • Cocoa:当光标位于 NSButton 上时更改光标

    当光标位于 NSButton 上时如何更改光标 您应该首先子类化 NSButton 然后添加以下代码 void resetCursorRects if self cursor self addCursorRect self bounds c
  • 更改asp.net core 2.2 IdentityUser的Id类型

    我是 dot net core 2 x 的新手 所以 我想将 asp net core 2 2 IdentityUser 中的 Id 类型从 string 更改为 int 我通过google 和stackoverflow搜索工具 找到的所有
  • 垂直对齐图像旁边的文本?

    为什么不会vertical align middle工作 但是 vertical align top does work span vertical align middle div img src https via placeholde
  • 如何用 ImageMagick 的命令覆盖 Windows 的转换命令?

    In Windows 一个名为convert用于转换文件系统 当您输入时convert 它会要求您指定一个文件系统 In 图像魔术师 convert命令用于图像处理 问题是 即使设置了 ImageMagick 的环境变量convert 该工
  • 创建对象的成本高吗?

    我刚刚重构了一位同事的代码 大致看起来像这样 public class Utility public void AddHistoryEntry int userID HistoryType Historytype int companyID
  • 在 MapView 中搜索注释

    我关注了一个如何使用 apples mapkit 搜索位置 https www thorntech com 2016 01 how to search for location using apples mapkit 关于搜索annotat
  • 高效找到 50k 2D 坐标的 n 个最近邻?

    我有一个包含纬度和经度的数组 任务是找到所有坐标的5个最近的坐标 而不是每次都循环遍历所有坐标 有几种解决方案 具体取决于您的数据 您对此一无所知 以及您想要的确定程度 如果您的数据是均匀分布的 那么您可以在数据之上创建一个网格并将点分配给
  • 具有“SA_SIGINFO”的 macOS“sigaction()”处理程序不包含“si_pid”

    我正在尝试编写一个信号处理程序 它需要知道发送信号的进程的 pid 我没有运气从那里得到任何有用的东西siginfo t使用 Xcode 10 传递到 macOS 10 14 上的处理程序 我已将代码减少到以下最小示例来演示该问题 在此示例