I am sure I am missing something obvious but my problem is as follows.
As a programming exercise I am trying to create an async posix message queue server to handle incoming messages asynchronously in a handler.
Now according to my documentation sigaction(2), mq_notify(3) and sigevent(7) my thought process should work. Before I post my code I'll outline my thought process on how it should be working.
- Using
sigaction
andSA_SIGINFO
I will set the signal handler forSIGIO
. - Using
mq_notify
andstruct sigevent
I will tell my message queue to sendSIGIO
to the current process when a message arrives. - By placing a pointer to my
mqd_t
for my message queue into thestruct sigevent.sigen_value.sigval_ptr
I will be able to retrieve this value in my signal handler throughstruct siginfo
. - As
sigevent(7)
tells me that whenSIGEV_SIGNAL
is set insigev_notify
thensi_code
,si_signo
andsi_value
are set in the signal handler'ssiginfo
. Specificallysi_value
is set to the value passed in forsigev_value
when callingmq_nofity
. - In my signal handler I should be able to get my message queue's
mqd_t
by doing something like(mqd_t *)(info->si_value.sival_ptr)
where info is thesiginfo_t*
passed as an argument to my signal handler. I have mymqd_t
in a structmq_info_t
as I will later do some more stuff with this.
Now my problem seems to be stemming from something different, but I thought I would outline my thought process in case it is somehow relevant. According to sigaction(2)
, siginfo_t
is a large struct containing all sorts of information, including si_value
.
Now in my gdb I am getting the error that my siginfo_t
in my signal handler does not have a member named si_value
. The same idea is mentioned in this question here.
(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 = 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}}}
Looking at where siginfo_t
is defined for my build I found that the structure defined in /usr/include/bits/types/siginfo_t.h
had the same structure. I am thinking this is some issue to do with the feature macros of my builds but I am do not know much in that area. My build has #define _POSIX_C_SOURCE 199309L
.
Now the key components of my code are as follows
#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;
}
Thanks in advance, I hope I have provided all relevant infromation.
Arch Linux w 5.3.8 kernel