Using mq and libmq instead of mqueue

Hi!

There is a new service with the name mq (a new
message-queue-server) in qnx neutrino 6.3.0.
So far I used the mqueue -service instead of mq. In the former
software
project I don’t use libmq. Now I want to use a mq-server instead of
mqueue-server. I added the library libmq to the project and ran mq
on the qnx-pc. After I started the new executable (now with libmq) I
get errors. This errors looks like errors I got when I ran the former
software project without a running mqueue -server in the background.

What is necessary to be changed in the former software project?

Thanks and best regards,
MOSTMAN

MOSTMAN wrote:

There is a new service with the name mq (a new
message-queue-server) in qnx neutrino 6.3.0.
So far I used the mqueue -service instead of mq. In the former
software project I don’t use libmq. Now I want to use a mq-server instead
of mqueue-server. I added the library libmq to the project and ran mq
on the qnx-pc. After I started the new executable (now with libmq) I
get errors. This errors looks like errors I got when I ran the former
software project without a running mqueue -server in the background.

What is necessary to be changed in the former software project?

You must link your software against libmq (if by “project” you mean
the IDE I don’t know how you specify this; in our Makefile world this
is simply “LIBS += mq”).

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi!

With the new mq (libmq & mq) you must strictly and only use
the mq_* functions with it. If you do something like:

mqd = mq_open();
read( mqd, buf, size) or write(mqd, buf, size)
it will not work.

Otherwise, need more details:

Did you try running mqueue on the target, instead of mq? If so,
did that make the errors go away? If so, that strongly suggests
you didn’t get the linking setup correctly. Take a look at the C-Build
output in the IDE, and make sure there is a -lmq issued at link time.

If running mqueue instead of mq doesn’t solve things, this suggests
codeing issues like I mentioned above.

-David


There is a new service with the name mq (a new
message-queue-server) in qnx neutrino 6.3.0.
So far I used the mqueue -service instead of mq. In the former
software
project I don’t use libmq. Now I want to use a mq-server instead of
mqueue-server. I added the library libmq to the project and ran mq
on the qnx-pc. After I started the new executable (now with libmq) I
get errors. This errors looks like errors I got when I ran the former
software project without a running mqueue -server in the background.

What is necessary to be changed in the former software project?

Thanks and best regards,
MOSTMAN


David Gibbs
QNX Training Services
dagibbs@qnx.com

Hi,

thanks for your replies. The cause for the problems aren’t wrong
linking or treating the returned descriptor as
a file descriptor. The problem is that mq_open() returns an error: Bad
Address (EFAULT).
The parameter of mq_open look like:
mq_open(name, O_RDWR | O_CREAT | O_EXCL, S_IPERMS, pMsg)

(char name) contains ‘’
pMsg contains:
|- mq_maxmsg: 500
|- mq_msgsize: 108
|- mq_flags: 0
|- mq_curmsgs: 0
|- mq_sendwait: 0
|- mq_recvwait: 0
According to stat.h:
#define S_IPERMS 000777 /
Permission mask */

With this parameters and running the server mq in the background I got
this error (EFAULT).
What is the reason for this?

Hi,

One thing wrong in my text:
(char *name) isn’t ‘’
The string looks like “\abc_def” or “\ghi_jkl_mno”.

Best regards

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi,

One thing wrong in my text:
(char *name) isn’t ‘’
The string looks like “\abc_def” or “\ghi_jkl_mno”.

Are you really using \ (back slash) characters in your
strings? In C (and Unix) this is an escape, which says
treat the next character as a special character of some
sort. e.g. “\n” is a newline. I’m pretty sure it won’t
be valid in a pathname.

Try starting the pathnames with a ‘/’ (forward slash) character.

If that fixes things, it is likely that the wrong errno is
being generated/propagated somewhere for the .

If not, EFAULT generally means a pointer probelm. Are you
testing this in a small test app, or as part of something
bigger? If in the small case, can you post the application
you’re testing with? If in the larger, can you try this in
an absolutely minimal test application?

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

MOSTMAN wrote:

The problem is that mq_open() returns an error: Bad Address (EFAULT).

This could be PR/22733, which is an incompatability between mq server
and the kernel implementation of async message queues. I think this
my have been present in 6.3.0, and was fixed in SP1.

The string looks like “\abc_def” or “\ghi_jkl_mno”.

As an aside, you should use ‘/’ and not ‘’ in the queue names.

Hi!

Thanks for your helps!!
Problem was I didn’t install SP1.
Now I can read and write into the mq - Message Queue.
In the former SW-Project there are operations of treating the with
mq_open() created
Message Queue-descriptor like a file descriptor
such as FD_SET
to add the m.q.-descriptor to the File-Deskr.-Set
to check with select() if new messages arrived in the message queue.
Can I solve this problem by using mq_notify()?

Thanx, best regards

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi!

Thanks for your helps!!
Problem was I didn’t install SP1.

That would cause problems, yes.

Now I can read and write into the mq - Message Queue.
In the former SW-Project there are operations of treating the with
mq_open() created
Message Queue-descriptor like a file descriptor
such as FD_SET
to add the m.q.-descriptor to the File-Deskr.-Set
to check with select() if new messages arrived in the message queue.
Can I solve this problem by using mq_notify()?

If they were ONLY using select() for mqs, you can fairly easily work
around this with mq_notify(). (See below…)

If they were using select() for mq_ds, and for sockets, pipes, consoles,
or anything else filedescriptor based, the structure starts to get a bit
more complicated. If this is the case, if the code was multiplexing through
select() for mqueues and non-mqueues, this is a non-portable use of mqueues
(POSIX does not require that this be possible) though many implementations
do allow it, including our mqueue implementation. But, for this case, it
may be worth examining why you wish to switch to mq, rather than mqueue,
and whether the code complexity introduced is worth it. Were you seeing
performance problems/bottlenecks with mqueue? Were you moving big messages,
or lots of messages, and the savings in mq is worth the cost of the code
changes? It may not be worth switching. If you do switch, the two main
methods would be to go multi-threaded, one thread for select() on non mqs,
the other for mq_notify() on mqs. This does require proper mutexing of any
and all shared data structures, conflicting code paths, and all the other
complexities of a threaded implementation. The other choice would be to
convert to mq_notify() for the mqs, and io_notify() for all the other fds.
(See below on mq_notify useage.)

If you were only using select() for mqueues, then the conversion to
mqs is not too bad. If you want to maintain a POSIX environment, you
would have to use signals, and I’d use data carrying signals, but I
would generally prefer to do this using pulses. (Signals cause some…
complications… cause they interrupt things, but with queued data
carrying signals, properly masked, you should do ok.)

Basic structure:

chid = ChannelCreate();
coid = ConnectAttach( chid, … _NTO_SIDE_CHANNEL, … );
for each queue:
mqd_t = mq_open(…, O_NONBLOCK,…);
SIGEV_PULSE_INIT( &ev, coid, CODE_MQUEUE, mqd_t); // value is mqd
mq_notify(mq_d, &ev );
// drain queue
while( (ret = mq_receive()) != -1 && errno != EWOULDBLOCK )
process queue entry or error
while(1)
MsgReceive()
if (msg.pulse.code == CODE_MQUEUE )
mqd = msg.pulse.value.sival_int;
SIGEV_PULSE_INIT( &ev, coid, CODE_MQUEUE, mqd); // value is mqd
mq_notify(mqd, &ev );
// drain queue
while( (ret = mq_receive()) != -1 && errno != EWOULDBLOCK )
process queue entry or error


Keys: mq_notify() is 1) only empty to non-empty for read, and 2) removed
after each notification, so: must attach notification, then drain to empty
to activate, then on each notification must attach notification then drain
to empty else will never be notified again.

Maybe you want to just stick with select() and mqueue? :wink:

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

Hi!

Thanks again for your help.
Now I have the problem that a Filedescriptor(created with mq_open() )
in the old software is duplicated with dup().
How can I duplicate this new kind of descriptor?

Best regards
MOSTMAN

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi!

Thanks again for your help.
Now I have the problem that a Filedescriptor(created with mq_open() )
in the old software is duplicated with dup().
How can I duplicate this new kind of descriptor?

To the best of my knowledge, you can’t. mq descriptors are
not file descriptors, and file descriptor operations are not
expected to map to them.

This does raise the question – why were you dup()ing your
mqueue descriptor? Do you need to dup() it?

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

Hi,

There are to many positions on which the function with dup() is be
called.
Is there a possibility to duplicate the descriptor in any way?
I thought to use mq_open() with the same parameters to create a new
descriptor. It fails with “Bad Address”.

What can I do to duplicate the descriptor?
Best regards,
MOSTMAN

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi,

There are to many positions on which the function with dup() is be
called.
Is there a possibility to duplicate the descriptor in any way?
I thought to use mq_open() with the same parameters to create a new
descriptor. It fails with “Bad Address”.

What can I do to duplicate the descriptor?

You can’t duplicate it. Again, why do you need a duplicate mqd?

A dup() on an fd basically gives you a second fd that shares file,
file offset, file mode, etc with the first one, so that operations
on the original, or the dup()ed one, should be interchangeable. This
generally only matters if you need an fd with a particular value, or you
need some sort of “reference count” for different things sharing acces,
which might be closing independently.

Needing an fd with a particular value is generally only important if
you’re spawning children, and you want the child to get/know that a
particular fd is stdin, or queue to receive on, or something like that.
Now, fds are inherited from parent to child, but mqd_ts (with libmq)
are not. So, dup()s in setting up for a child are useless. If you need
to get such mq information to a child, you’ll probably have to recode it
so that you pass the mq name on the command line to the child, and have
the child do the mq_open().

Now, if you are using it for convenient reference counting for
mq_open/mq_close, maybe for multi-threading, or for references in
different internal structures/classes, then you would probably have
to cover the mq_open/mq_close/dup with your own function – the dup()
cover would just return the exact same mqd_t value back, and these
covers would maintain a reference count, and only on an mq_close()
that drops the reference count to 0, would you actually issue the
mq_close() to the server.

Now, maybe you’re dup()ing for some other reason I haven’t thought of.
But, the possible solutions/suggestions I can make depend on why you’re
dup()ing an mqd_t, which is why I asked.

And, of course, this goes back to… do you need the performance gains
of mq (vs mqueue) enough to be worth all this code mangling?

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

Hi!

Got it!
A possibility is to choose mq_open(“description_of_mq”, O_RDWR). The
description must be
saved at the point where the descriptor is created, for example
storing it in a table:

|1 | /abc |
|2 | /def |
|3 | /etc |

If you have a global access to this table, you can create a new
descriptor.
Not a beatiful solution, I know.

MOSTMAN

MOSTMAN wrote:

There are to many positions on which the function with dup() is be
called.

A “mq” mqd_t is not a file descriptor. Under “mqueue” is happens to
be, but portable code shouldn’t assume that to be the case, and
should just stick to the POSIX mq_*() routines.

Is there a possibility to duplicate the descriptor in any way?

You can just mq_open() it again. Since dup() creates a copy which
shares file offset, and for mq there is no such thing - all reads
and writes happen at defined head/tail queue position - the offset
is irrelevant. So in this case a dup() should be equivalent to
another mq_open (just have to know the queue name instead of
descriptor).

David Gibbs wrote:

Now, fds are inherited from parent to child, but mqd_ts
(with libmq) are not.

FYI, it is a POSIX requirement of “fork()” that “The child process
shall have its own copy of the message queue descriptors of the
parent”. So they are inherited in this case.

MOSTMAN <christian.richter@soft-gate-dot-de.no-spam.invalid> wrote:

Hi!

Got it!
A possibility is to choose mq_open(“description_of_mq”, O_RDWR). The
description must be
saved at the point where the descriptor is created, for example
storing it in a table:

|1 | /abc |
|2 | /def |
|3 | /etc |

If you have a global access to this table, you can create a new
descriptor.
Not a beatiful solution, I know.

No, but if you were dup()ing descriptors, you had to have a way to
track the ones you wanted to dup() as well.

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

John Garvey <jgarvey@qnx.com> wrote:

David Gibbs wrote:
Now, fds are inherited from parent to child, but mqd_ts
(with libmq) are not.

FYI, it is a POSIX requirement of “fork()” that “The child process
shall have its own copy of the message queue descriptors of the
parent”. So they are inherited in this case.

Ah, ok. I asked xtang, and he had thought they weren’t inherited.

So you get them inherited, but you can’t play with what mdq_t number
you get as you might with dup/dup2.

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com