si_value 不是 siginfo_t 内部 sigaction 处理程序的成员,使用 POSIX 消息队列

si_value not a member of siginfo_t inside sigaction handler using POSIX message queues

我确定我遗漏了一些明显的东西,但我的问题如下。

作为一个编程练习,我正在尝试创建一个异步 posix 消息队列服务器以在处理程序中异步处理传入消息。

现在根据我的文档 sigaction(2), mq_notify(3) and sigevent(7) 我的思维过程应该可行了。在我 post 我的代码之前,我将概述我对它应该如何工作的思考过程。

现在我的问题似乎源于不同的东西,但我想我会概述我的思考过程,以防它在某种程度上是相关的。根据 sigaction(2)siginfo_t 是一个包含各种信息的大型结构,包括 si_value.

现在在我的 gdb 中我得到一个错误,我的信号处理程序中的 siginfo_t 没有名为 si_value 的成员。这个问题here.

中提到了同样的想法

(gdb) p *info = {si_signo = 29, si_errno = 0, si_code = -3, __pad0 = 0, _sifields = {_pad = {128611, 1000, -8896, 32767, 0 }, _kill = {si_pid = 128611, si_uid = 1000}, _timer = {si_tid = 128611, si_overrun = 1000, si_sigval = { sival_int = -8896, sival_ptr = 0x7fffffffdd40}}, _rt = {si_pid = 128611, si_uid = 1000, si_sigval = {sival_int = -8896, sival_ptr = 0x7fffffffdd40}}, _sigchld = {si_pid = 128611, si_uid = 1000, si_status = -8896, si_utime = 0, si_stime = 0}, _sigfault = {si_addr = 0x3e80001f663, si_addr_lsb = -8896, _bounds = {_addr_bnd = {_lower = 0x0, _upper = 0x0}, _pkey = 0}}, _sigpoll = {si_band = 4294967424611, si_fd = -8896}, _sigsys = {_call_addr = 0x3e80001f663, _syscall = -8896, _arch = 32767}}}

查看为我的构建定义 siginfo_t 的位置,我发现 /usr/include/bits/types/siginfo_t.h 中定义的结构具有相同的结构。我认为这是与我构建的功能宏有关的一些问题,但我对该领域知之甚少。我的构建有 #define _POSIX_C_SOURCE 199309L.

现在我的代码的关键组成部分如下

#define _POSIX_C_SOURCE 199309L
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <mqueue.h>
#include <string.h>

typedef struct mq_info {
    mqd_t fd;
} mq_info_t;

/** Handler for receiving async messages */
void sigHandler(int signal, siginfo_t *info, void *context)
{
    char buffer[MAX_SIZE + 1];
    int must_stop = 0;
    ssize_t bytes_read;
    mq_info_t *mq_i = (mq_info_t *)(info->si_value.sival_ptr);
    mqd_t mq = mq_i->fd;

    printf("In handler\n");

    do {
        bytes_read = mq_receive(mq, buffer, MAX_SIZE, NULL);

        printf("MQ received: %s\n", buffer);
    } while (bytes_read > 0);

    printf("left handler\n");
}

int openMessageQueue(char *name, long max_msg_num, long max_msg_size)
{
    mq_info_t *mq_i = calloc(1, sizeof(mq_info_t));
    struct mq_attr attr;
    struct sigaction sa;
    struct sigevent ev;
    union sigval sv = { .sival_ptr = &mq_i };

    attr.mq_flags = O_NONBLOCK; // Async
    attr.mq_maxmsg = max_msg_num;
    attr.mq_msgsize = max_msg_size;
    attr.mq_curmsgs = 0; // Num of messages currently in queue

    if (-1 == (mq_i->fd = mq_open(name, O_CREAT | O_RDONLY, 0644, &attr)))
        goto error;

    printf("queue opened\n");

    /** Setup handler for SIGIO */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = sigHandler;
    printf("Sighandler: %p\n", sigHandler);
    sigfillset(&sa.sa_mask);
    sigdelset(&sa.sa_mask, SIGIO);
    if (sigaction(SIGIO, &sa, NULL))
        goto error;

    printf("sigaction done\n");

    /** Set up process to be informed about async queue event */
    ev.sigev_notify = SIGEV_SIGNAL; // Specify a signal should be sen
    ev.sigev_signo = SIGIO; // Signal of interest
    ev.sigev_value =
        sv; // Suplementary data passed to signal handling fuction
    ev.sigev_notify_function = NULL; // Used by SIGEV_THREAD
    ev.sigev_notify_attributes = NULL; // Used by SIGEV_THREAD

    /** Register this process to receive async notifications when a new message  */
    /**     arrives on the specified message queue  */
    if (mq_notify(mq_i->fd, &ev) < 0) {
        perror("notify failed");
        goto error;
    }

    printf("notify done\n");

    return 0;

error:
    mq_unlink(name);
    return -1;
}

提前致谢,希望我提供了所有相关信息。

Arch Linux w 5.3.8 内核

查看 bits/types/siginfo_t.h 的最底部,您会看到:

/* X/Open requires some more fields with fixed names.  */
#define si_pid          _sifields._kill.si_pid
#define si_uid          _sifields._kill.si_uid
#define si_timerid      _sifields._timer.si_tid
#define si_overrun      _sifields._timer.si_overrun
#define si_status       _sifields._sigchld.si_status
#define si_utime        _sifields._sigchld.si_utime
#define si_stime        _sifields._sigchld.si_stime
#define si_value        _sifields._rt.si_sigval
// ...

因此,在您的代码中,当您编写 info->si_value.sival_ptr 时,它会被宏扩展为 info->_sifields._rt.si_sigval.sival_ptr 并且编译器 "proper" 很高兴。但是 GDB 不知道 si_value 的宏定义,所以你必须在从调试器访问该字段时自己输入它。

(是的,这太可怕了,但我们不能在不破坏 ABI 的情况下清理它。)

(你为什么使用 #define _POSIX_C_SOURCE 199309L?这不是你问题的直接原因,但你可能会更乐意使用更现代的一致性模式,我建议 #define _XOPEN_SOURCE 700 用于新代码应该在当前一代的 Unix 中是可移植的。)