SysV IPC

msgsnd#

Send a message to a System V IPC message queue.

msgsnd is a thin wrapper around the msgsnd(2) syscall. It appends MSG to the queue identified by ID (the queue id previously returned by msgget), and returns true on success or false on error with $! set. MSG is not free-form: it must start with a native long message type, followed by the payload bytes. FLAGS control blocking and error-on-overflow behaviour, typically 0 or IPC_NOWAIT.

Synopsis#

msgsnd ID, MSG, FLAGS

What you get back#

True on success, false on failure. On failure $! is set to the errno from msgsnd(2) — common values are EAGAIN (queue full, IPC_NOWAIT was set), EIDRM (queue was removed), EINTR (signal interrupted a blocking call), and EACCES (no write permission on the queue).

Because the return value is a plain boolean, always check it before assuming the message was enqueued:

msgsnd($qid, $msg, 0)
    or die "msgsnd($qid) failed: $!";

Message format#

The kernel reserves the first sizeof(long) bytes of every queued message for the message type, a positive long integer that msgrcv callers use to select which messages to dequeue. The payload follows, uninterpreted.

Build the buffer with pack using the l! (native long) and a* (raw bytes) specifiers:

my $type    = 1;
my $payload = "hello queue";
my $msg     = pack("l! a*", $type, $payload);
msgsnd($qid, $msg, 0) or die "msgsnd: $!";

The message type must be greater than zero. Zero and negative values are reserved for the selector semantics of msgrcv and cause msgsnd(2) to fail with EINVAL.

Global state it touches#

  • $! — set to the errno from the failed syscall when msgsnd returns false. Untouched on success.

Examples#

Send a simple typed message with the default blocking behaviour. If the queue is full, the call waits until space is available:

use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR);

my $qid = msgget(IPC_PRIVATE, IPC_CREAT | S_IRUSR | S_IWUSR)
    // die "msgget: $!";

my $msg = pack("l! a*", 1, "job-42");
msgsnd($qid, $msg, 0) or die "msgsnd: $!";

Non-blocking send — return immediately with EAGAIN in $! if the queue is full, rather than sleeping:

use IPC::SysV qw(IPC_NOWAIT);
use Errno qw(EAGAIN);

unless (msgsnd($qid, $msg, IPC_NOWAIT)) {
    if ($! == EAGAIN) {
        warn "queue full, dropping message\n";
    } else {
        die "msgsnd: $!";
    }
}

Use the type field as a priority / channel tag. Receivers pick by type via msgrcv:

my %CHANNEL = (log => 1, metric => 2, alert => 3);

sub send_event {
    my ($kind, $body) = @_;
    my $msg = pack("l! a*", $CHANNEL{$kind}, $body);
    msgsnd($qid, $msg, 0) or die "msgsnd[$kind]: $!";
}

send_event(alert  => "disk > 90%");
send_event(metric => "rps=1240");

Send a structured payload — pack the header fields after the mandatory type prefix:

my $type = 1;
my $body = pack("N N a*", $job_id, $retry_count, $payload);
msgsnd($qid, pack("l! a*", $type, $body), 0)
    or die "msgsnd: $!";

Edge cases#

  • Message type must be positive. Passing 0 or a negative type fails with EINVAL. The type-selection semantics in msgrcv reserve those values for selector logic.

  • Message exceeds msg_qbytes. If MSG is larger than the queue’s configured per-message limit, msgsnd fails with EINVAL regardless of FLAGS. Check and raise the limit with msgctl IPC_SET if you control the queue.

  • Queue full without IPC_NOWAIT. The call blocks until another process dequeues, the queue is removed (EIDRM), or a signal interrupts it (EINTR). Retry on EINTR if the signal is expected and benign.

  • Queue full with IPC_NOWAIT. Fails immediately with EAGAIN. This is the only way to enforce bounded latency on the send side.

  • Missing type prefix. Forgetting to pack the l! type prefix passes the raw payload as-is; the first sizeof(long) bytes are then interpreted as the type — typically a large positive or negative number — and the rest as the body. Receivers filtering by type see nothing.

  • ID is a queue id, not a key. Pass the integer returned by msgget, not the KEY you gave to msgget. Confusing the two yields EINVAL or, worse, a successful send to an unrelated queue that happens to share the numeric value.

  • Permissions. The process must have write permission on the queue (the w bit of the queue’s mode for its effective uid/gid). Otherwise the call fails with EACCES.

  • Tainting. MSG is read as a byte string; no taint checking is performed on it here. If MSG came from an untrusted source, the receiver side (msgrcv, which does taint its output) is where filtering belongs.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • msgget — obtain the queue id passed as ID; call this first, or receive the id from whoever created the queue

  • msgrcv — the matching receive primitive; its TYPE argument selects against the l! prefix written here

  • msgctl — inspect the queue’s msg_qbytes limit or remove the queue when done

  • pack — build the l! a* buffer msgsnd requires; also the tool for any further structure inside the payload

  • $! — carries the errno from a failed msgsnd; compare against Errno constants to branch on specific failures