How to open a message queue on QNX?

Hi, guys,

I am a freshout in China. I feel so glad to meet all of u and exchange my ideas with u here.

I got a problem about how to open a new message queue. I failed when I tried to open a new queue. Below is my source code.

#define MQ_PERMISSION (S_IRWXU | S_IRWXG | S_IRWXO)

    char               mq_name[100];
    struct mq_attr     mq_attr_ds;
    uint32_t          mq_counter = 0;
    ... ...
    mq_attr_ds.mq_maxmsg = 1024;   /* maximum number of messages */
    mq_attr_ds.mq_msgsize = 100;  /* maximum message size */
    strcpy(mq_name[mq_counter], "/tmq");
    spaH_printf("Mq error information: %s",strerror(errno));

    mq_name[mq_counter][4] = '0' + mq_counter/10;
    mq_name[mq_counter][5] = '0' + mq_counter%10;

    mq_id_array[mq_counter] =
    mq_open(mq_name[mq_counter],
            O_CREAT | O_RDWR, MQ_PERMISSION, &mq_attr_ds);

    spaH_printf("Mq error information: %s",strerror(errno));

    if (mq_id_array[mq_counter] == (mqd_t)-1) {
        spaH_printf("\nFail to open message queue %s!\n",
                    mq_name[mq_counter]);
        break;
    }
    else {
        spaH_printf("Open message queue %s!\n", mq_name[mq_counter]);
    }

And the output message on QNX is:

Mq error information: No such file or directory
Start to open a new message queue.
Mq error information: No such file or directoryMq error information: No such file or directory
Fail to open message queue /tmq00!

Could u please tell me where is my mistake? And what’s the key point when opening a message queue on QNX?

Many Thanks,
Yongjie

Jongjie,

Your example code is a bit more complex that it needs to be. :slight_smile:

According to the documentation, there only 2 ways you can get the error of “No such file or directory” (ENOENT).

  1. You fail to specify O_CREAT when the queue does not exist
  2. You opened the queue and failed to close it properly

Your example definitely is doing #1. But I suspect your problem is #2.

You can get #2 if your program ran once and you didn’t do an mq_close() before your program exited. If that happens, mqueue keeps the queue open forever and when you try to create it again it always fails.

To fix this you need to restart mqueue and then make sure to do an mq_close in your program before it exits.

Tim

This can’t be real code you can have:

char mq_name[100];

and then

mq_name[mq_counter][4] …

Also paH_printf(“Mq error information: %s”,strerror(errno)); after a strcpy is useless. What function do you expect to have set errno? errno is set only on error, it’ the same for the printf after the mq_open. Typicaly you’d use errno only when an error is detected.

First of all, thanks for your help. U r friendly enough.

mario is correct. I modified some code to make others easy to understand it. But I made a mistake. I am sorry.

I modified location of printf function. And I used errno only when an error is detected.

Also, I cleared mq_attr data structure at the beginning. mq_attr data structure was initialized after mq_open() call.

But finally, I still failed to open it.

Below is my source code.
perror("\nPart 3 …\n");
mq_attr_ds.mq_maxmsg = 0; /* maximum number of messages /
mq_attr_ds.mq_msgsize = 0; /
maximum message size */
mq_attr_ds.mq_flags = 0;
mq_attr_ds.mq_curmsgs = 0;
mq_attr_ds.mq_sendwait = 0;
mq_attr_ds.mq_recvwait = 0;

for (mq_counter = 0; ; mq_counter++) {
    perror("Start to open a new message queue.");

    strcpy(mq_name[mq_counter], "/tmq");

    mq_name[mq_counter][4] = '0' + mq_counter/10;
    mq_name[mq_counter][5] = '0' + mq_counter%10;

    mq_id_array[mq_counter] =
    mq_open(mq_name[mq_counter],
            O_CREAT | O_RDWR, MQ_PERMISSION, NULL);
    if (mq_id_array[mq_counter] == (mqd_t)-1) {
        spaH_printf("Mq error information: %s",strerror(errno));
        perror("Fail to open message queue!");
        break;
    }
    else {
        spaH_printf("Open message queue %s!\n", mq_name[mq_counter]);
    }
    mq_attr_ds.mq_maxmsg = 1024;   /* maximum number of messages */
    mq_attr_ds.mq_msgsize = 128;  /* maximum message size */
    mq_attr_ds.mq_flags = 0;
    mq_attr_ds.mq_curmsgs = 0;
    mq_attr_ds.mq_sendwait = 0;
    mq_attr_ds.mq_recvwait = 0;

}
spaH_printf("\nThere have been %d message queues created.\n",
                   mq_counter);

for (i = 0; i < mq_counter; i++) {
    id = mq_close(mq_id_array[i]);
    if (id == -1) {
        spaH_printf("Mq error information: %s",strerror(errno));
        spaH_printf("Fail to close message queue %s!\n",
                    mq_name[i]);
    }
}

for (i = 0; i < mq_counter; i++) {
    id = mq_unlink(mq_name[i]);
    if (id == -1) {
        spaH_printf("Mq error information: %s",strerror(errno));
        perror("Fail to remove message queue!");
    }
}

Below is output message on QNX.
Part 3 …
: No error
Start to open a new message queue.: No error
Fail to open message queue!: No such file or directory

There have been 0 message queues created.

Result - Error code: 0IPC: MsgSend(): rc:0
IPC: spa_apps_diag_ipc: spa_msg_hdr: 269 1 36 0

Waiting for message … … …

It can be working on Solaris. But I have tried many times on QNX. It didn’t work. I have no idea what’s the point. All my dear friends, could u gimme any suggestions?

Thanks,
Yongjie

Yongjie,

On my system, the following code works just fine:

if (mq_open("/tmq0", O_CREAT | O_RDWR, 777, NULL) == -1)
{
printf(“Fail %d\n”, errno);
}
else
{
printf(“Success\n”);
}

I always get the success case printed.

As I said above, the documentation says there is only 2 reasons for failure. One of them, not using O_CREAT is NOT your issue. So it has to be the other one.

I’d do the following if I were you:

  1. Make sure the mqueue process is running (use the pidin command)
  2. Slay mqueue and restart it (as root) or reboot completely to make sure your in a known starting state.
  3. Add a line of ‘unlink(mq_name[mq_counter]);’ just BEFORE you do the mq_open. This ensures old queues from prior iterations of your program running are completely removed.
  4. Try and get a simple example line of mq_open to work like I posted above where you hardcode everything. Once you get something like ‘mq_open("/Foo", O_CREAT | O_RDWR, 777, NULL);’ to work it might help explain why your main code is not working.

Tim

Hi, Tim,

Thanks for your help! I followed your instruction but I failed again. I presume there are two following reasons.

  1. Maybe we don’t have the appropriate file system setup to use message queues.

  2. Maybe we have the file system set up but the permissions are such that the message queue cannot be created.

I will be trying. If I have good news, I would like to share my happiness with u.

Thanks,
Yongjie

Yongje,

  1. I am not sure what you mean by this. There isn’t anything to set up in terms of the file system in order to use mqueue. The only other thing you might consider doing is removing the leading ‘/’ in your queue name. That would make the queue be created locally in the directory where your program is running instead of in /dev/mqueue. It shouldn’t make any difference but it’s worth at least trying.

  2. I can’t imagine any reason for that since you create or are attempting to create the queues. Before you run your program, take a look in /dev/mqueue and make sure either /dev/mqueue/yourqueuename doesn’t already exist there (if it does, remove it).

I am assuming that you do have mqueue running as a process (you can check with pidin command).

Tim

While everyone jumps at the problem itself, I would like to ask why message queues are to be used in this case. They are usually quite slow compared to native, synchronous message passing of QNX Neutrino. I know that in some cases message queues make more sense, but I’ve often seen people use them because message queues exist in many OS’s and as such, are used because it seems a matter of course to use them. But in Neutrino, I’d only use them as a last resort and try MsgSend/MsgReceive first. It’s faster and also leads to a much cleaner design, usually.

Tim, et al.

Many thanks for your insights and help. I work on the same team as Yongjie (just in a slightly different area).

First, we belive the problem was that when we where handed the QNX environment to do investigation and testing, it did not have the mqueue process started.

Thanks to Tims comments, it spawned a flurry of activities and knoweldge for getting a console session to the embedded system to actually interface with the QNX shell and do some of these activites. Yeah, I know… we should have had this sort of access from the start, but thats another story – to compound things more, we are not very savy with QNX environment configuration (but we are learning).

I’m not sure if Yongjie has successfully completed his mqueue exercise now that we have the mqueue process started, but I am hopeful. Moreover, Yongjie’s exercise is to do some investigating into QNX’s interactions with various POSIX elements such as message queues and their limits, clocks, etc. (We anticipated and have encountered some differences between QNX and Solaris.)

As for why message queues? We are working on a product that has three operating systems to run on: QNX, Solaris and RT-Linux. As such the lead designer pushed for POSIX compliant messaging to minimize platform dependent differences, and thats how we came to message queues.

Right or wrong, thats where we are at today. However, I am more than happy to learn of other methods, and why one might be better than another.

Since you are exploring POSIX message queue on QNX, may I also mention the new message queue implementation, “mq” ? :slight_smile:

POSIX Message Queue, is implemented on QNX, with a “manager process”, which now you know, called “mqueue”.
Programs calling “mq_*()” functions, endup talking to the “manager process” to get work done.

But this kind of implementation leads to performance issue, QNX laterly released a new set of Message Queue
imeplementation. The “manager process” in this implementation, called “mq”. I don’t remember is it 6.30
or SP1 this goes out, but if you have a /sbin/mq, then you have it.

To use the new “mq” implementation, you need to start “mq” instead of “mqueue”, and your application need
to link with “libmq.so” (-lmq).

The advantage of using new “mq” is the performance, some says it’s 10 times faster then older “mqueue”
implementation. The “dis-advantage” is the new “mq” implementation can’t cross QNET.

A simple demo program using mqueue is attached, works in 6.3

A simple demo program using mqueue is attached, works in 6.3

// Works in QNX 6.3.0 SP 2
// Adapted from users.pjwstk.edu.pl/~jms/qnx … rview.html

#include <mqueue.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define MSG_SIZE 4096
#define MQ_PRIO_MAX 16
// This handler will be called when the queue
// becomes non-empty.
int SIG_NUM;
void handler (int sig_num) {

SIG_NUM = sig_num;

}

int main () {
struct mq_attr attr, old_attr; // To store queue attributes
struct sigevent sigevent; // For notification
mqd_t mqdes; // Message queue descriptor
char buf[MSG_SIZE]; // A good-sized buffer
unsigned int prio; // Priority

SIG_NUM = 0;

// First we need to set up the attribute structure
attr.mq_maxmsg = 300;
attr.mq_msgsize = MSG_SIZE;
attr.mq_flags = 0;

// Open a queue with the attribute structure
mqdes = mq_open (“line_1”, O_RDWR | O_CREAT,
0664, &attr);

// Get the attributes
mq_getattr (mqdes, &attr);
printf ("%d messages are currently on the queue.\n",
(int)attr.mq_curmsgs);

if (attr.mq_curmsgs != 0) {

// There are some messages on this queue....eat them

// First set the queue to not block any calls    
attr.mq_flags = O_NONBLOCK ;
mq_setattr (mqdes, &attr, &old_attr);    
    
// Now eat all of the messages
while (mq_receive (mqdes, &buf[0], MSG_SIZE, &prio) != -1) 
  printf ("Received a message with priority %d.\n", prio);
        
// The call failed.  Make sure errno is EAGAIN
if (errno != EAGAIN) { 
  perror ("mq_receive()");
  _exit (EXIT_FAILURE);
}
    
// Now restore the attributes
mq_setattr (mqdes, &old_attr, 0);            

}

// We want to be notified when something is there

signal (SIGUSR1, handler);
sigevent.sigev_signo = SIGUSR1;
sigevent.sigev_notify = SIGEV_SIGNAL ;

if (mq_notify (mqdes, &sigevent) == -1) {
if (errno == EBUSY)
printf (
“Another process has registered for notification.\n”);
_exit (EXIT_FAILURE);
}

for (prio = 0; prio <= MQ_PRIO_MAX; prio += 8)
{
if ( SIG_NUM != 0)
{
printf (“Received sig %d.\n”, SIG_NUM);
SIG_NUM = 0;
}
printf (“Writing a message with priority %d.\n”, prio);
if (mq_send (mqdes, “I8-)”, 4, prio) == -1)
perror (“mq_send()”);
}

// Close all open message queue descriptors
mq_close (mqdes);

return (1);

}

hello_mq.zip