System V Message Queues Message Queue Limits

 

System V Message Queues
Chapter 46 · Section 46.5 — Message Queue Limits
5
Limit Constants
3
/proc Files
2
Code Examples

Key Concepts in This Section
MSGMNI MSGMAX MSGMNB MSGTQL MSGPOOL /proc/sys/kernel IPC_INFO msginfo struct ENOSPC EINVAL EAGAIN zero-length messages

Why Do Message Queue Limits Exist?

The Linux kernel is shared by all running processes. If a single process were allowed to create thousands of message queues and fill each with gigabytes of data, it would starve other processes of resources. To prevent this, the kernel enforces system-wide limits on message queues.

These limits control three things: how many queues can exist simultaneously, how large a single message can be, and how much data a single queue can hold at one time. Understanding these limits is essential for writing robust IPC code — especially in embedded Linux systems or server applications where resource budgets are tight.

Key Insight: These are system-wide limits, not per-process. All message queues on the entire system share the same MSGMNI, MSGMAX, and MSGMNB ceilings. Individual queues can have their own msg_qbytes tuned lower than MSGMNB, but never higher (unless privileged).

The Three Limits Enforced by Linux

These three limits are the primary constraints. When any of these is hit, a specific system call fails with a specific error code.

MSGMNI msgget() → ENOSPC

What it controls: The maximum number of message queue identifiers (i.e., message queues) that can exist simultaneously on the entire system.

What happens when reached: Any attempt to create a new message queue with msgget(IPC_CREAT, ...) fails with errno = ENOSPC.

Default value (Linux 2.6.31, x86-32): 748 queues
Maximum ceiling: 32768 (defined as IPCMNI in the kernel)
/proc file: /proc/sys/kernel/msgmni

On modern Linux systems the default MSGMNI is often set higher (e.g. 32000) and may be auto-scaled to system RAM. Always verify on your target system.
MSGMAX msgsnd() → EINVAL

What it controls: The maximum number of bytes in the mtext field of a single message. This is a hard ceiling on individual message size.

What happens when reached: msgsnd() fails with errno = EINVAL if you try to send a message whose mtext length exceeds MSGMAX.

Default value: 8192 bytes (8 KB)
Maximum ceiling: Depends on available system memory
/proc file: /proc/sys/kernel/msgmax

Design Warning: If your protocol needs to pass large payloads, do NOT increase MSGMAX beyond a few tens of kilobytes. Message queues are not designed for large data — use shared memory instead and pass a pointer/key via the message queue.
MSGMNB msgsnd() blocks or EAGAIN

What it controls: The maximum total number of bytes (of mtext data) that a single message queue can hold at one time. This is the initial value assigned to msg_qbytes in msqid_ds when a new queue is created.

What happens when reached: msgsnd() blocks until a receiver drains the queue. If IPC_NOWAIT is specified, it fails with errno = EAGAIN.

Default value: 16384 bytes (16 KB)
Maximum ceiling: 2147483647 (INT_MAX)
/proc file: /proc/sys/kernel/msgmnb

After queue creation, each queue’s msg_qbytes can be individually tuned via msgctl(IPC_SET) — but an unprivileged process cannot set it above MSGMNB. MSGMNB also controls the per-queue upper bound for unprivileged processes.

Limit Summary Table (from TLPI Table 46-1)
Limit Name What It Limits Error When Reached Default (x86-32, Linux 2.6.31) Maximum Ceiling /proc File
MSGMNI Number of message queues on system ENOSPC (msgget) 748 32768 (IPCMNI) /proc/sys/kernel/msgmni
MSGMAX Max bytes per single message EINVAL (msgsnd) 8192 bytes Depends on memory /proc/sys/kernel/msgmax
MSGMNB Max bytes per queue (init value for msg_qbytes) Blocks or EAGAIN (msgsnd) 16384 bytes 2147483647 (INT_MAX) /proc/sys/kernel/msgmnb

Two Further Limits: MSGTQL and MSGPOOL

Some UNIX implementations define two additional limits. Linux does not enforce these directly, but they appear in older documentation and other OS man pages.

MSGTQL Not enforced on Linux

The system-wide maximum number of messages (across all queues combined). Linux does not impose this limit globally but instead limits the number of messages per queue indirectly through msg_qbytes.

MSGPOOL Not enforced on Linux

The total size of the kernel buffer pool used to hold message data across all queues. Again, Linux does not impose a MSGPOOL global; it relies on the general VM subsystem to limit memory usage.

Linux Approach Instead: Linux limits per-queue message count indirectly. The number of messages allowed is bounded by msg_qbytes: even zero-length messages count as 1-byte equivalent to prevent infinite queuing of zero-byte messages (each still consumes kernel bookkeeping memory).

Special Case: Zero-Length Messages

It is legal to send a message with an mtext size of 0 bytes. However, even though the message carries no data, it still consumes kernel overhead (for bookkeeping, the message header, etc.). Without a limit on these, a process could flood the queue with infinite zero-length messages.

Linux handles this by treating zero-length messages as equivalent to 1-byte messages when counting against the msg_qbytes limit. So the maximum number of zero-length messages you can put in a queue equals the maximum number of 1-byte messages — which is bounded by msg_qbytes.

Design Note: Zero-length messages are sometimes used as pure signals — just to notify another process that something happened, without passing any data. They are not “free” in kernel resource terms.

Viewing and Changing Limits via /proc

Linux exposes all three enforced limits as readable/writable files under /proc/sys/kernel/. This means you can:

  • Read current limit: cat /proc/sys/kernel/msgmni
  • Change limit (as root): echo 2048 > /proc/sys/kernel/msgmni
  • Make permanent across reboots: add to /etc/sysctl.conf

Changes to MSGMNB via /proc affect all subsequently created message queues (the initial msg_qbytes for new queues), as well as raising the ceiling for unprivileged IPC_SET calls on existing queues.

Example shell session (from TLPI):
$ cat /proc/sys/kernel/msgmni → 748
$ cat /proc/sys/kernel/msgmax → 8192
$ cat /proc/sys/kernel/msgmnb → 16384

Querying Limits Programmatically: IPC_INFO and msginfo

Instead of reading /proc files, your program can query the kernel for all message queue limits at once using the Linux-specific msgctl(IPC_INFO) operation. This fills a struct msginfo with the current values of all limits.

The struct msginfo includes fields such as:

Field Corresponds To
msgmni MSGMNI — max queues on system
msgmax MSGMAX — max bytes per message
msgmnb MSGMNB — max bytes per queue
msgtql MSGTQL — (implementation-defined)
msgpool MSGPOOL — (implementation-defined)
Note: IPC_INFO is Linux-specific and not portable to other UNIX systems. The first argument to msgctl() in this case is ignored (pass 0 by convention). The third argument must be cast to (struct msqid_ds *) even though you are passing a struct msginfo *.

Code Example 1 — Reading Limits from /proc/sys/kernel

This program reads all three system-wide message queue limits from the /proc filesystem and prints them in a human-readable form.

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

/* Helper: read a single integer from a /proc file */
static long read_proc_int(const char *path)
{
    FILE *fp;
    long val;

    fp = fopen(path, "r");
    if (fp == NULL) {
        perror(path);
        return -1;
    }
    if (fscanf(fp, "%ld", &val) != 1)
        val = -1;
    fclose(fp);
    return val;
}

int main(void)
{
    long msgmni, msgmax, msgmnb;

    msgmni = read_proc_int("/proc/sys/kernel/msgmni");
    msgmax = read_proc_int("/proc/sys/kernel/msgmax");
    msgmnb = read_proc_int("/proc/sys/kernel/msgmnb");

    printf("===== System V Message Queue Limits =====\n\n");
    printf("MSGMNI  (max queues on system)  : %ld\n", msgmni);
    printf("MSGMAX  (max bytes per message) : %ld bytes\n", msgmax);
    printf("MSGMNB  (max bytes per queue)   : %ld bytes\n", msgmnb);
    printf("\n");
    printf("Notes:\n");
    printf("  - Unprivileged IPC_SET: msg_qbytes max = MSGMNB (%ld)\n", msgmnb);
    printf("  - Privileged IPC_SET : msg_qbytes max = INT_MAX (2147483647)\n");
    printf("  - To change: echo VALUE > /proc/sys/kernel/msgmni (as root)\n");
    return 0;
}
Run as a normal user to observe current defaults. These values vary by kernel version and distribution. On modern kernels, MSGMNI may be much higher (e.g., 32000).

Code Example 2 — Querying Limits with IPC_INFO

This program uses the Linux-specific IPC_INFO operation of msgctl() to read the msginfo structure and display all message queue limits programmatically (no file I/O needed).

#define _GNU_SOURCE          /* Required to get IPC_INFO and struct msginfo */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/msg.h>

int main(void)
{
    struct msginfo info;

    /*
     * IPC_INFO: Linux-specific operation.
     * First arg (msqid) is ignored — pass 0.
     * Cast the msginfo pointer to (struct msqid_ds *) as required by API.
     * Returns the highest occupied slot in the message queue table.
     */
    if (msgctl(0, IPC_INFO, (struct msqid_ds *) &info) == -1) {
        perror("msgctl IPC_INFO");
        exit(EXIT_FAILURE);
    }

    printf("===== msginfo (from IPC_INFO) =====\n\n");
    printf("msgmni  (max queues)            : %d\n", info.msgmni);
    printf("msgmax  (max bytes/message)     : %d bytes\n", info.msgmax);
    printf("msgmnb  (max bytes/queue)       : %d bytes\n", info.msgmnb);
    printf("msgtql  (max total messages)    : %d\n", info.msgtql);
    printf("msgpool (kernel buffer pool KB) : %d\n", info.msgpool);
    return 0;
}
Compilation Note: You must define _GNU_SOURCE before including the headers to get the definitions of IPC_INFO and struct msginfo. Without it, the compiler will report that IPC_INFO is undeclared.

Interview Questions
Q1. Name the three System V message queue limits enforced by Linux and what each controls.
MSGMNI — the maximum number of message queues (identifiers) that can exist simultaneously on the system. MSGMAX — the maximum number of bytes in the mtext of a single message. MSGMNB — the maximum total bytes allowed in a single queue at one time (used to initialize msg_qbytes).
Q2. What error does msgsnd() return when a message is larger than MSGMAX?
msgsnd() fails with errno = EINVAL. This is a hard error — the message is simply too large to ever fit in a single send. The solution is either to reduce the message size or increase MSGMAX via /proc/sys/kernel/msgmax (as root).
Q3. What error does msgget() return when MSGMNI is reached?
msgget() fails with errno = ENOSPC — meaning there is no space (no free message queue slot) available in the kernel’s IPC table. To resolve this, either remove unused queues or increase MSGMNI via /proc/sys/kernel/msgmni.
Q4. What is the relationship between MSGMNB and msg_qbytes?
MSGMNB is the system-wide default value. When a new message queue is created, msg_qbytes in the associated msqid_ds is initialized to MSGMNB. After creation, msg_qbytes can be changed per-queue via msgctl(IPC_SET) — but an unprivileged process cannot raise it above MSGMNB. MSGMNB also serves as the ceiling for IPC_SET by unprivileged processes.
Q5. Does Linux enforce MSGTQL or MSGPOOL? How does it achieve the same goal?
No, Linux does not enforce MSGTQL (total messages across all queues) or MSGPOOL (total buffer pool size) as separate limits. Instead, Linux limits messages on a per-queue basis through each queue’s msg_qbytes. Zero-length messages are treated as equivalent to 1-byte messages, preventing unbounded queuing of zero-byte signals.
Q6. How do you view current message queue limits on a running Linux system?
You can read them from the /proc filesystem:
cat /proc/sys/kernel/msgmni — number of queues
cat /proc/sys/kernel/msgmax — max bytes per message
cat /proc/sys/kernel/msgmnb — max bytes per queue
Programmatically, use msgctl(0, IPC_INFO, (struct msqid_ds*)&buf) with struct msginfo.
Q7. How do you change a limit permanently across reboots?
Writing to /proc/sys/kernel/msgmni (etc.) changes the value only until the next reboot. To make it permanent, add the corresponding line to /etc/sysctl.conf:
kernel.msgmni = 2048
kernel.msgmax = 65536
kernel.msgmnb = 65536
Then run sysctl -p to apply without rebooting.
Q8. Why does Linux impose a limit on zero-length messages?
Even a zero-length message consumes kernel memory for bookkeeping overhead (the message header, internal list pointers, etc.). Without a limit, a malicious or buggy process could send an unbounded number of zero-length messages, exhausting kernel memory. Linux prevents this by counting zero-length messages as 1-byte equivalent against the queue’s msg_qbytes limit.
Q9. What feature-test macro must you define to use IPC_INFO and struct msginfo?
You must define _GNU_SOURCE before including the IPC header files. This macro unlocks GNU/Linux extensions that are not part of the POSIX standard. Without it, the compiler will not see the IPC_INFO constant or the struct msginfo definition.
Q10. If msgsnd() blocks because msg_qbytes is full, what two ways can the situation resolve?
(1) Another process calls msgrcv() on the same queue, removing one or more messages and freeing space. The blocked msgsnd() is then unblocked and proceeds. (2) The message queue is removed with msgctl(IPC_RMID) — in this case the blocked msgsnd() returns with errno = EIDRM. If instead IPC_NOWAIT was used, it would never have blocked in the first place — it would have returned EAGAIN immediately.

Leave a Reply

Your email address will not be published. Required fields are marked *