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
和 SA_SIGINFO
我将为 SIGIO
设置信号处理程序。
- 使用
mq_notify
和 struct sigevent
我将告诉我的消息队列在消息到达时将 SIGIO
发送到当前进程。
- 通过将指向我的消息队列的
mqd_t
的指针放入 struct sigevent.sigen_value.sigval_ptr
,我将能够通过 struct siginfo
在我的信号处理程序中检索该值。
- As
sigevent(7)
告诉我,当 SIGEV_SIGNAL
设置为 sigev_notify
时, si_code
、si_signo
和 si_value
设置为信号处理程序的 siginfo
。具体来说,si_value
设置为调用 mq_nofity
时为 sigev_value
传入的值。
- 在我的信号处理程序中,我应该能够通过执行类似
(mqd_t *)(info->si_value.sival_ptr)
的操作来获取消息队列的 mqd_t
,其中信息是作为参数传递给我的信号处理程序的 siginfo_t*
。我的 mqd_t
在一个结构 mq_info_t
中,因为稍后我会用它做更多的事情。
现在我的问题似乎源于不同的东西,但我想我会概述我的思考过程,以防它在某种程度上是相关的。根据 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 中是可移植的。)
我确定我遗漏了一些明显的东西,但我的问题如下。
作为一个编程练习,我正在尝试创建一个异步 posix 消息队列服务器以在处理程序中异步处理传入消息。
现在根据我的文档 sigaction(2), mq_notify(3) and sigevent(7) 我的思维过程应该可行了。在我 post 我的代码之前,我将概述我对它应该如何工作的思考过程。
- 使用
sigaction
和SA_SIGINFO
我将为SIGIO
设置信号处理程序。 - 使用
mq_notify
和struct sigevent
我将告诉我的消息队列在消息到达时将SIGIO
发送到当前进程。 - 通过将指向我的消息队列的
mqd_t
的指针放入struct sigevent.sigen_value.sigval_ptr
,我将能够通过struct siginfo
在我的信号处理程序中检索该值。 - As
sigevent(7)
告诉我,当SIGEV_SIGNAL
设置为sigev_notify
时,si_code
、si_signo
和si_value
设置为信号处理程序的siginfo
。具体来说,si_value
设置为调用mq_nofity
时为sigev_value
传入的值。 - 在我的信号处理程序中,我应该能够通过执行类似
(mqd_t *)(info->si_value.sival_ptr)
的操作来获取消息队列的mqd_t
,其中信息是作为参数传递给我的信号处理程序的siginfo_t*
。我的mqd_t
在一个结构mq_info_t
中,因为稍后我会用它做更多的事情。
现在我的问题似乎源于不同的东西,但我想我会概述我的思考过程,以防它在某种程度上是相关的。根据 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 中是可移植的。)