POSIX Message Queues on Small Linux Images: Validate Limits and Namespace Visibility

Qualify POSIX message queues through the actual mq API, effective limits and IPC namespace before blaming a missing /dev/mqueue directory. The filesystem mount is an inspection view; it is not the queue’s API name. A service also needs a lifecycle for persistent queue names, compatible attributes and cleanup after failed startup.

This guide uses Linux man-pages 6.12 for modern Linux POSIX queues, which differ from System V queues and RTOS in-memory queues. The executed fixture created one tiny, uniquely named host queue, immediately unlinked its name and closed it after bounded checks. It did not change mounts, namespaces or system limits.

Separate build support from runtime availability

The Linux queue overview identifies CONFIG_POSIX_MQUEUE as the kernel configuration gate. Check the shipped kernel’s effective configuration where available, the target libc’s headers and link requirements, and the final service binary. A host development machine exposing mqueue.h does not prove the embedded image can execute the calls.

Use a minimal target probe with explicit error reporting. Distinguish a missing declaration or link symbol from a runtime syscall failure, permission error or resource limit. If an environment returns ENOSYS, inspect the actual kernel and syscall policy rather than assuming the image version from that error alone.

The traditional link interface uses librt; the executed host fixture included -lrt. Exact library organization varies with libc release, so preserve the real compile/link command instead of asserting that every modern toolchain requires a separate runtime library file.

Three qualification stages cover image API capability, namespace and resource admission, then receive-buffer and queue-lifecycle contracts, with bounded host fixture results below.
Original queue acceptance map. Namespace, inspection mount, queue attributes and object lifetime are distinct boundaries.

Use API names and namespace identity correctly

A queue API name has the form /name with an initial slash and no additional slashes. It is not /dev/mqueue/name. The mqueue filesystem can expose names for inspection when mounted, but absence of that mount path alone does not establish that mq_open is unavailable.

IPC namespaces isolate POSIX message queue objects and their mqueue control interfaces. Two processes using the same string in different IPC namespaces do not thereby open the same queue. Record the producer and consumer’s namespace relationship as well as their visible filesystem layout.

When troubleshooting a service inside a container or sandbox, compare its own API results and namespace identity with the peer’s. A shell outside that environment may list a different set of objects. Do not mount filesystems or join namespaces merely as an automatic diagnostic step; inspect the intended deployment design first.

Choose explicit attributes for a new queue

The mq_open contract uses mq_maxmsg and mq_msgsize from the supplied attribute structure when creating a queue. Its mq_flags and mq_curmsgs fields are not creation controls. Select O_NONBLOCK in the open flags when the intended fixture must never wait for capacity or data.

Use O_CREAT with O_EXCL for an owned qualification queue so an old object cannot silently supply unexpected attributes or messages. The creation mode is subject to umask. For a production shared name, define which component creates it, which merely opens it, and how both verify the resulting attributes before exchanging messages.

Limit or attribute What it constrains
mq_maxmsg / mq_msgsize The individual queue’s maximum count and message size.
msg_max / msgsize_max Normal creation ceilings in the relevant mqueue context.
queues_max Queue-count admission, distinct from per-queue fullness.
RLIMIT_MSGQUEUE Accounting for queues associated with the real user ID, including kernel overhead.
Descriptor limits Ability to obtain another open queue descriptor.

Read the effective values instead of copying documented defaults as product requirements. The RLIMIT_MSGQUEUE accounting includes more than mq_maxmsg multiplied by payload size. A small payload total does not prove a creation request must fit the user’s remaining budget.

Read back attributes and size the receiver

After open, call mq_getattr and check maximum count, maximum message size and current occupancy. Existing queue attributes are not replaced simply because a later opener supplies a new desired structure. Treat incompatible attributes as a version or stale-object problem, not as permission to unlink a queue another process still owns.

The mq_receive contract requires the destination buffer to be at least the queue’s configured mq_msgsize, even if the next actual message is shorter. A too-small receive buffer fails with EMSGSIZE. Size the buffer from validated attributes and a product maximum before accepting an arbitrary existing queue.

Messages are delivered highest priority first, with the oldest message selected within that priority. If FIFO order across all messages matters, define a consistent priority policy. A successful send means queue admission, not completion of the receiver’s application action; add request/result semantics where the product needs them.

Define persistence and unlink ownership

POSIX queues have kernel persistence: a named queue can survive the creating process’s exit until removed or the containing environment is destroyed. That explains old messages or unexpected attributes after a service-only restart. It is not storage persistence across a system shutdown.

mq_unlink removes the name immediately, while the object remains until its open references close. A new queue can later be created under the same name while old holders still refer to the previous object. Avoid using the name alone as a guarantee that all participants share one generation.

Assign one lifecycle owner and define startup collision, orderly shutdown and crash recovery. Do not automatically unlink every matching name from a shared namespace. For a private fixture, immediate unlink after successful exclusive creation is useful cleanup discipline because the process can continue testing through its open descriptor without leaving a stale name after a later failure.

Executed bounded probe and remaining tests

A GCC 14.2.0 host fixture created a nonblocking queue with two-message capacity and 32-byte maximum messages. It read those attributes back, unlinked its unique name, sent low- and high-priority messages, and observed EAGAIN on a third send. An eight-byte receive buffer returned EMSGSIZE; a 32-byte buffer then received priority three before priority one. An empty receive returned EAGAIN, and the descriptor was closed.

This demonstrates the host API and selected attribute/ordering boundaries on x86-64 Linux 6.18.44. It does not qualify a minimal target image, multiple namespaces, user-budget exhaustion or cross-process startup races. Proposed target tests add those deployment boundaries using bounded owned resources and an explicit cleanup owner.

The release artifact should include kernel/libc identities, namespace relationship, effective limits, readback attributes and queue-generation policy. That makes a queue failure diagnosable without mistaking a missing inspection mount, a full queue and an incompatible persistent object for the same problem.

Similar Posts