POSIX message queues allow for an efficient, priority-driven IPC mechanism
with multiple readers and writers. For the experienced POSIX programmer,
this description invokes an image of named pipes. However, there are some
fundamental differences between pipes and message queues:

Message queues have internal structure. With a named pipe, a writer
is just pumping bits. For a reader, there's no distinction between
different calls to write() from different writers.
It's left up to the
programmer to make sure that the correct number of bits are put into or
taken out of the pipe. This makes variable-sized messages a hassle.

Message queues are priority-driven. Whenever a writer sends a
message to a queue, a priority is specified for that message. The
queue will remain sorted such that the oldest message of the highest
priority will always be at the front.

The programmer has control over the geometry of a message queue.
When a message queue is created, the programmer may set ceilings on the
number of messages that can be on the queue, and the size of each
message.

A process can determine the status of a message queue. One
major drawback of pipes is that their state is unknown. With message
queues, a process can determine how many messages on the queue, the
various maximums and flags that have been set, and the number of
processes that are blocking to either send or receive.

Of course, message queues in the QNX implementation still have all of the
advantages of named pipes (FIFOs in QNX):

They exist in the pathname space.

They can have POSIX permissions.

They can be accessed using the traditional I/O routines
(such as open(),
read(), write(), select() and so on).

For more information, see "POSIX.4 Message Queues" in the
Better Coordination: Messages,
Shared Memory, and Synchronization chapter of Programming for the
Real World - POSIX.4 by Bill O. Gallmeister (O'Reilly &
Associates, Inc. ISBN: 1-56592-074-0).

Like pipes and FIFOs, all message queue operations are performed
based on message queue descriptors (an mqd_t).
In the QNX implementation, an mqd_t is a file descriptor.
Thus, in addition to the POSIX message queue API, the programmer
may call almost any I/O routine that takes a file descriptor.

Every message queue has an attribute structure associated with
it. This structure includes:

longmq_flags

The options set for this queue. This field may have been
changed since queue creation with a call to mq_setattr()
(see below for a
description of each bit).

longmq_maxmsg

The maximum number of messages that can be stored on the
queue. In the QNX implementation, an mq_maxmsg of 0 means
that there is no maximum. This value was set when the queue was
created.

longmq_msgsize

The maximum size of each message on the given message queue.
This value was also set when the queue was created.

longmq_curmsgs

This field represents the number of messages currently on the
given queue.

longmq_sendwait

The number of processes currently waiting to send a message.
This field was eliminated from the POSIX standard after draft 9, but has
been resurrected for the QNX implementation. A nonzero value in this
field implies that the queue is full.

longmq_recvwait

The number of processes currently waiting to receive a
message. Like mq_sendwait, this field was resurrected for
the QNX implementation. A nonzero value in this field implies that the
queue is empty.

The mq_flags field is the bitwise OR of zero or more of the
constants described below.

The following constant is specified by POSIX 1003.4:

MQ_NONBLOCK

No mq_receive() or mq_send() will ever block on
this queue. If the queue is in such a condition that the given operation
cannot be performed without blocking, then an error is returned, and
errno is set to EAGAIN.

The following constants are unique to the QNX implementation:

MQ_MULT_NOTIFY

When this flag is set, more than one process may be registered for
notification; a call to mq_notify() never returns an
EBUSY error. If multiple processes are registered for
notification, then they are notified on a first come, first served
basis. This flag may only be set on; it may never be set off. Any
attempt to set this flag off once it is on causes errno
to be set to EINVAL.

MQ_NOTIFY_ALWAYS

When this flag is set, the mq_notify() call causes
the process to be notified, even if the queue currently contains
messages.

MQ_PRIO_RESTRICT

The POSIX 1003.4 standard allows any process to send a message of
arbitrary
priority. This may allow low-priority processes to wield excessive power.
If this flag is set, then no process may use mq_send() to
send a message with a priority higher than its own. An attempt to do so
causes errno to be set to EINVAL.

MQ_PRIO_BOOST

By default, any write() to a message queue sends a
message with priority 0. If this option is in effect, then any time a
zero-priority message is written, its priority is boosted to that
of the calling process. This option only affects messages with
a priority of 0.

MQ_READBUF_DYNAMIC

POSIX mandates that an mq_receive() performed on a queue
with a buffer size less than that queues maximum message size must fail. However, it is very possible that a process could have a receive buffer
of significantly smaller size than the maximum, and still never miss
data. If this flag is set, processes may make calls to
mq_receive() with arbitrary buffer sizes. The call only
fails if a message that has a size larger than the buffer allotted
is about to be received. In this case, an error is returned, and
errno is set to EINVAL.

To compile, a program must include the <mqueue.h> header file.
This header file is found in the /usr/include directory.

In order to use any of the API specific to message queues, a program must be
linked with the mqueue library in the /usr/lib
directory.
This library file contains
the client-side stubs for these calls. Add the following to your compile
command so that the compiler can find the libraries:

-l mqueue

For a program using message queues to run, the message queue server must
first be running. This can be started by typing:

Mqueue &

If you wish to connect to an Mqueue server on a different node,
set the MQ_NODE environment variable accordingly. The
mq_open() stub checks
this variable to determine on which node to seek out the server.
For more information, see the QNX Utilities Reference.

The first time the example program is run, the output should be
as follows:

$ mq_test
0 messages are currently on the queue.
Writing a message with priority 0.
Received sig 16.
Writing a message with priority 8.
Writing a message with priority 16.
Writing a message with priority 24.
Writing a message with priority 32.

After the program wrote to the empty queue, it was signalled that the queue
had made the transition from empty to nonempty. The second time the
example program is run, the following should be produced:

$ mq_test
5 messages are currently on the queue.
Received a message with priority 32.
Received a message with priority 24.
Received a message with priority 16.
Received a message with priority 8.
Received a message with priority 0.
Writing a message with priority 0.
Received sig 16.
Writing a message with priority 8.
Writing a message with priority 16.
Writing a message with priority 24.
Writing a message with priority 32.

Note that the first message received was the message with the highest
priority, with all of the other priorities following in suit.

Because all message queues exist in the pathname space, it's very easy for
end users to determine the status of a queue. From the shell, the user
must first change directories to the prefix owned by Mqueue:

$ cd /dev/mqueue

A simple ls may reveal the following:

/dev/mqueue $ ls
homer ned marge otto

This tells us that there are currently four message queues in the system.
To get more detailed information, try ls with the
"long listing" option:

This is a little more useful. Starting from the left, the n
in the first
column of each entry says that this is a special named file. This is so
something like vi knows that it shouldn't attempt to edit it.
Following the n, each entry has its permissions.
These are identical to file
permissions. In this case:

the user can read and write

the group can read and write

the rest of the world can only read

Following this we have a 1, which is meaningless.
If you can think of a useful stat to go
there (it's the st_status field) let QSSL know.
Following the 1, we
have the owner, the group, the number of messages currently on the queue
(right now all of these queues are empty), the time of creation, and
finally the name.

If you want a little more information, try the
little-used ls -i (this specifies the "inode" option,
and is useful for filesystems):

/dev/mqueue $ ls -i
1024 homer 1024 ned
1024 marge 1024 otto

Now we know the capacity of each of these queues (in this case, 1024
messages). Lets try sending something to our good friend Ned Flanders: