我确定我遗漏了一些明显的东西,但我的问题如下。
作为一个编程练习,我正在尝试创建一个异步 posix 消息队列服务器来在处理程序中异步处理传入的消息。
现在根据我的文档sigaction(2)、mq_notify(3)和sigevent(7)我的思考过程应该有效。在我发布我的代码之前,我将概述我关于它应该如何工作的思考过程。
- 使用
sigaction
andSA_SIGINFO
我将为SIGIO
. - 使用
mq_notify
andstruct sigevent
我会告诉我的消息队列SIGIO
在消息到达时发送到当前进程。 - 通过将指向我
mqd_t
的消息队列的指针放入struct sigevent.sigen_value.sigval_ptr
我将能够在我的信号处理程序中通过struct siginfo
. - 正如
sigevent(7)
告诉我 whenSIGEV_SIGNAL
设置在sigev_notify
thensi_code
中,si_signo
并且si_value
设置在信号处理程序的siginfo
. 具体si_value
设置为sigev_value
调用时传入的值mq_nofity
。 - 在我的信号处理程序中,我应该能够
mqd_t
通过执行类似(mqd_t *)(info->si_value.sival_ptr)
where infosiginfo_t*
作为参数传递给我的信号处理程序的操作来获取我的消息队列。我有我mqd_t
的结构mq_info_t
,因为我稍后会用这个做更多的事情。
现在我的问题似乎源于不同的东西,但我想我会概述我的思维过程,以防它在某种程度上相关。根据sigaction(2)
,siginfo_t
是一个包含各种信息的大型结构,包括si_value
.
现在在我的 gdb 中,我收到错误消息,即我siginfo_t
的信号处理程序中没有名为si_value
. 这个问题在这里提到了同样的想法。
(gdb) p *info $1 = {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 = 0x7ffffffffdd40}}, _rt = {si_pid = 128611, si_uid = 1000, si_sigval = {sival_int = -886 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_add = -88896 = 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 内核