I am writing a program that is intended to fork multiple processes, each of which open a unique message queue for receiving messages. Every time I run my program, however, every single forked process encounters the Bad address
error when initializing their respective queues with mq_open
.
My code is intended to generate message queue names dynamically, following the form "/_*
, where *
is some unique letter (a, b, c, etc.) However, upon trying the same code with the string "/hello"
put in place of the dynamically generated names, the program still failed with the same error.
This has led me to believe that the issue is a failure to create a new queue, rather than an issue with the name itself. However, I believe I am passing O_CREAT correctly, so I can't figure out what the problem is.
I did find this previous thread on the subject, but it doesn't seem that that guy was having the same problems. I believe I have included all relevant code below, but please let me know if more is needed. Any help is much appreciated!
Here is the wrapper function that actually calls mq_open
:
mqd_t init_queue(char *desc, long m_flags, long m_max, long m_size)
{
mqd_t mq_des;
struct mq_attr attr;
mode_t mode = 0664;
attr.mq_maxmsg = m_max;
attr.mq_msgsize = m_size;
attr.mq_flags = m_flags;
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
return mq_des;
}
Here is the function that calls init_queue
. I've pasted in the relevant macros and helper function (nid
) at the top as well, so you can see those:
#define DESCPREF "/_"
#define DESCSIZE 4
#define FIRSTID 97
#define MAXMSGS 200
#define M_SIZE sizeof(struct _message)
char *nid(int id)
{
char *desc = malloc(sizeof(char) * DESCSIZE);
char c = id;
snprintf(desc, DESCSIZE, "%s%c", DESCPREF, c);
return desc;
}
int node(int id, int inc)
{
/* INIT */
proc_info me = malloc(PROCINF_SIZE);
me->id = id;
me->curr = id - FIRSTID + 1;
me->inc = inc;
char *mypath = nid(id);
me->listen = init_queue(mypath, O_NONBLOCK, MAXMSGS, M_SIZE);
/* Do some stuff ... */
close_queue(me->listen);
mq_unlink(mypath);
free(me);
return 0;
}
Finally, the bit of code that forks my individual processes:
int main(){
pid_t pid;
int nodes = TESTNODES;
for (int i = 0; i < nodes; i++) {
if ((pid = fork()) == -1) {
perror("Fork error\n");
exit(1);
} else if (pid == 0) {
node(FIRSTID + i, nodes);
exit(0);
} else {
printf("Forked: %d\n", (int) pid);
}
}
return 1;
}
I would expect this code to simply run, printing the pids of forked processes, then exit. Instead I get the following errors (for one example run):
Forked: 27448
Forked: 27449
Error at init_queue: Bad address
Error at init_queue: Bad address
Forked: 27450
Error at init_queue: Bad address
Forked: 27451
Error at init_queue: Bad address
Forked: 27452
Error at init_queue: Bad address
As previously mentioned, I also tried this with the plain string "/hello"
used as the input name for mq_open
and received the same set of errors (all five failed in that case as well).
You need to pass the pointer to the mq_attr struct like:
if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, &attr)) == -1) {
perror("Error at init_queue");
exit(1);
}
also as per the manual page make sure the values for max messages and msg size make sense otherwise you will get an EINVAL.
EINVAL O_CREAT was specified in oflag, and attr was not NULL, but
attr->mq_maxmsg or attr->mq_msqsize was invalid. Both of
these fields must be greater than zero. In a process that is
unprivileged (does not have the CAP_SYS_RESOURCE capability),
attr->mq_maxmsg must be less than or equal to the msg_max
limit, and attr->mq_msgsize must be less than or equal to the
msgsize_max limit. In addition, even in a privileged process,
attr->mq_maxmsg cannot exceed the HARD_MAX limit. (See
mq_overview(7) for details of these limits.)