NAME
mq
, mqueue
— POSIX message queues
(REALTIME)
LIBRARY
library “librt”
SYNOPSIS
#include
<mqueue.h>
DESCRIPTION
The IEEE Std 1003.1-2001 (“POSIX.1”) standard defines and NetBSD implements an interprocess communication (IPC) interface known as POSIX message queues. Although the basic functionality is similar,mq
is distinct from
the older AT&T System V UNIX message queues
(see for example ipcs(1) or
msgget(2)).
Rationale
The rationale behind mq
is to provide an
efficient, priority-driven asynchronous IPC mechanism. When the
AT&T System V UNIX message queues were
first implemented, the reasoning was similar: the only form of IPC was
half-duplex pipes and message queues were seen to overcome the performance
limitations with these.
But arguably in modern systems there is little difference between
the efficiency of the System V message queues, pipes, and UNIX domain
sockets (if anything, the AT&T System V
UNIX message queues tend to be slower than the rest). The fundamental
performance bottleneck is however still there with
mq
as well: data must be first copied from the
sender to the kernel and then from the kernel to the receiver. The bigger
the message, the higher the overhead.
For realtime applications, mq
offers some
advantages:
- Unlike the predecessors,
mq
provides an asynchronous notification mechanism. - Messages are prioritized. The queue always remains sorted such that the oldest message of the highest priority is always received first, regardless of the number of messages in the queue.
- By default, the functions to send and receive messages are blocking calls.
It is however possible to use non-blocking variants with
mq
. Furthermore, it is possible to specify timeouts to avoid non-deterministic blocking. - Resource limits can be enforced -- or perhaps more importantly, the availability of resources can be ensured as the internal data structures are preallocated.
Descriptors and Naming
Comparable to pipes and FIFOs (a.k.a. named pipes), all POSIX message queue operations are performed by using a descriptor. The used type is mqd_t, an abbreviation from a “message queue descriptor”. In the NetBSD implementation this is actually an ordinary file descriptor. This means that it is possible, but not portable, to monitor a message queue descriptor by using poll(2) or select(2).
Message queues are named by character strings that
represent (absolute) pathnames. The used interface is analogous to the
conventional file concepts. But unlike FIFOs and pipes, neither POSIX nor
System V message queues are accessed by using
open(2), read(2), or
write(2). Instead, equivalents such as
mq_open
(),
mq_close
(),
and
mq_unlink
()
are used.
The standard does not specify whether POSIX message queues are
exposed at the file system level. It can be argued that
mq
inherited an old problem with the System V
message queues. Even if an implementation would have support for it, it is
not portable to view message queues by
ls(1),
remove these with rm(1), or adjust the permissions with
chmod(1).
Processes
When a new process is created or the program is terminated,
message queues behave like files. More specifically, when
fork(2) is called, files and message queues are inherited, and when
the program terminates by calling
exit(3) or
_exit(2), both file descriptors and message queues are closed.
However, the exec(3) family of functions behave somewhat differently for
message queues and files: all message queues are closed when a process calls
one of the
exec
()
functions. In this respect POSIX message queues are closer to FIFOs than
normal pipes.
Attributes
All message queues have an attribute associated with them. This is represented by the mq_attr structure:
struct mq_attr { long mq_flags; long mq_maxmsg; long mq_msgsize; long mq_curmsgs; };
The members in the structure are: flags set for the message queue (mq_flags), the maximum number of messages in the queue (mq_maxmsg), the maximum size of each message (mq_msgsize), and the number of queued messages (mq_curmsgs).
The overall resource requirements for a particular
message queue are given by mq_maxmsg and
mq_msgsize. These two can be specified when the queue
is created by a call to
mq_open
().
The constraints are enforced through the lifetime of the queue: an error is
returned if a message larger than mq_msgsize is sent,
and if the message queue is already full, as determined by
mq_maxmsg, the call to queue a message will either
block or error out.
Although there are two functions,
mq_getattr
()
and
mq_setattr
(),
to retrieve and set attributes, resource limits cannot be changed once the
queue has been created. In NetBSD the super user may
however control the global resource limits by using few
sysctl(7) variables.
Asynchronous Notification
Instead of blocking in the functions that receive messages,
mq
offers an asynchronous mechanism for a process to
receive notifications that messages are available in the message queue. The
function mq_notify
() is used to register for
notification. Either a signal or a thread can be used as the type of
notification; see
sigevent(3) for details.
Bear in mind that no notification is sent for an
arrival of a message to a non-empty message queue. In other words,
mq_notify
()
does not by itself ensure that a process will be notified every time a
message arrives. Thus, after having called
mq_notify
(), an application may need to repeatedly
call
mq_receive
()
until the queue is empty. This requires that the message queue was created
with the O_NONBLOCK
flag; otherwise
mq_receive
() blocks until a message is again queued
or the call is interrupted by a signal. This may be a limitation for some
realtime applications.
Priorities
Each message has a priority, ranging from 0 to the
implementation-defined MQ_PRIO_MAX
. The POSIX
standard enforces the minimum value of the maximum priority to be 32. All
messages are inserted into a message queue according to the specified
priority. High priority messages are sent before low priority messages. If
the used priority is constant, mq
follows the FIFO
(First In, First Out) principle.
The basic rule of thumb with realtime prioritization is that low priority tasks should never unnecessarily delay high priority tasks. Priority inheritance is not however part of the provided API; the receiver process may run at low priority even when receiving high priority messages. To address this limitation and other potential realtime problems, the user may consider other functions from the library “librt”. The process scheduling interface described in sched(3) can be mentioned as an example.
FUNCTIONS
The following functions are available in the API.
Function | Description |
mq_open(3) | open a message queue |
mq_close(3) | close a message queue |
mq_unlink(3) | remove a message queue |
mq_send(3) | send a message |
mq_receive(3) | receive a message |
mq_timedsend(3) | send a message with a timeout |
mq_timedreceive(3) | receive a message with a timeout |
mq_getattr(3) | get message queue attributes |
mq_setattr(3) | set message queue attributes |
mq_notify(3) | register asynchronous notify |
COMPATIBILITY
Despite of some early fears, the POSIX message queue implementations are fairly compatible with each other. Nevertheless, few points can be noted for portable applications.
- It is not portable to use functions external to the API with message queue descriptors.
- The standard leaves the rules loose with respect to the message queue names. Only the interpretation of the first slash character is consistent; the following slash characters may or may not follow the conventional construction rules for a pathname.
- The length limits for a message queue name are implementation-defined.
These may or may not follow the conventional pathname limits
PATH_MAX
andNAME_MAX
.
SEE ALSO
Bill O. Gallmeister, POSIX.4: Programming for the Real World, O'Reilly and Associates, 1995.
Richard W. Stevens, UNIX Network Programming, Volume 2: Interprocess Communications, Prentice Hall, Second Edition, 1998.
STANDARDS
The POSIX message queue implementation is expected to conform to IEEE Std 1003.1-2001 (“POSIX.1”).
HISTORY
The POSIX message queue API first appeared in NetBSD 5.0.
CAVEATS
User should be careful to unlink message queues at the program termination. Otherwise it is possible to leave them lying around.