SysV IPC

msgrcv#

Receive a message from a System V IPC message queue.

msgrcv is the Perl binding for the msgrcv(2) syscall. It pulls one message off the queue identified by ID, stores the message type and payload into VAR, and returns a truthy value on success or false on error. SIZE is the maximum number of payload bytes the caller is willing to accept; TYPE selects which message to receive; FLAGS is the bitmask passed to the kernel (IPC_NOWAIT, MSG_NOERROR, etc.).

The returned buffer is not just the message body — the first sizeof(long) bytes are the message type the sender passed to msgsnd, followed by the payload. Use unpack with the l! a* template to split them apart.

Synopsis#

use IPC::SysV qw(IPC_NOWAIT MSG_NOERROR);

msgrcv $qid, my $buf, 1024, 0, 0            or die "msgrcv: $!";
msgrcv $qid, my $buf, 1024, 0, IPC_NOWAIT;  # non-blocking
my ($type, $payload) = unpack "l! a*", $buf;

What you get back#

True on success, false on error with $! set. On success, VAR is overwritten with the received frame: a native long (the message type) immediately followed by up to SIZE bytes of payload. The variable is marked tainted under -T.

VAR is grown or shrunk to fit the actual frame length — you do not need to pre-size it. The content before the call is discarded.

To get the type and payload as separate values:

my ($type, $msg) = unpack "l! a*", $buf;

Arguments#

  • ID — the queue id previously returned by msgget.

  • VAR — a lvalue scalar that receives the raw frame. Its previous value is discarded on success.

  • SIZE — the maximum payload size in bytes. If the next matching message is larger than this, msgrcv fails with E2BIG and the message stays on the queue — unless MSG_NOERROR is set in FLAGS, in which case the message is truncated silently and the extra bytes are lost.

  • TYPE — selects which message to receive:

    • 0 — the first message on the queue, whatever its type.

    • positive N — the first message whose type is exactly N.

    • negative -N — the first message of the lowest type that is <= abs(N), useful for priority queues.

  • FLAGS — bitmask of IPC_NOWAIT (return ENOMSG immediately instead of blocking when no matching message is available), MSG_NOERROR (truncate instead of failing on oversized messages), and the Linux-specific MSG_EXCEPT (with a positive TYPE, receive the first message whose type is not TYPE).

The constants live in IPC::SysV; the bare names do not become visible until you import them.

Global state it touches#

  • $! — set on error to the underlying errno (ENOMSG, E2BIG, EIDRM, EINVAL, EACCES, EFAULT, EINTR).

  • Taint mode — the received VAR is marked tainted, since its contents came from another process.

Examples#

Blocking receive of any message, then split type and payload:

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

my $qid = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR) // die "msgget: $!";
msgrcv $qid, my $buf, 4096, 0, 0            or die "msgrcv: $!";
my ($type, $payload) = unpack "l! a*", $buf;
print "got type=$type payload=$payload\n";

Receive only messages of type 42:

msgrcv $qid, my $buf, 4096, 42, 0           or die "msgrcv: $!";

Non-blocking poll — return immediately if the queue is empty:

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

if (msgrcv $qid, my $buf, 4096, 0, IPC_NOWAIT) {
    my ($type, $msg) = unpack "l! a*", $buf;
    handle($type, $msg);
} elsif ($! == ENOMSG) {
    # queue was empty; try again later
} else {
    die "msgrcv: $!";
}

Truncate oversized messages rather than failing:

use IPC::SysV qw(MSG_NOERROR);

msgrcv $qid, my $buf, 64, 0, MSG_NOERROR    or die "msgrcv: $!";
# payload is at most 64 bytes, excess discarded without error

Priority-style receive — take the lowest-numbered message whose type is <= 3:

msgrcv $qid, my $buf, 4096, -3, 0           or die "msgrcv: $!";

Edge cases#

  • VAR must be an lvalue. Passing a constant or a read-only scalar (for instance an element of @_ that was passed by reference to a literal) raises Modification of a read-only value attempted.

  • Frame layout is native long, not four bytes. On 64-bit Linux the type occupies 8 bytes; on 32-bit systems it occupies 4. The l! in unpack "l! a*" — the ! — is mandatory; a plain l assumes 4 bytes and will corrupt payloads on 64-bit hosts.

  • SIZE excludes the type header for MSG_NOERROR purposes. The kernel compares SIZE against the payload length, not the frame length. Size the buffer for the largest payload you expect; the type header is written beyond it.

  • Signal interruption. A blocking msgrcv returns false with $! == EINTR when a signal arrives before a message is available. Retry the call unless the signal is meant to abort the receive loop.

  • Queue removed while blocked. If another process calls msgctl with IPC_RMID while this process is asleep in msgrcv, the call returns false with $! == EIDRM.

  • Permissions. Receiving requires read permission on the queue. EACCES means the queue exists but the current uid/gid doesn’t match the queue’s mode bits.

  • TYPE = 0 sees FIFO order. There is no “any” priority short of explicit negative TYPE — messages of all types are pulled in send order.

  • Kernel support. Linux kernels built without CONFIG_SYSVIPC, and container runtimes that don’t expose the IPC namespace, fail every msgrcv with ENOSYS. Check during startup if your deployment target is uncertain.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • msgsnd — the counterpart that puts messages on the queue; its pack "l! a*" template is the inverse of what you unpack here

  • msgget — obtain the queue id ID you pass in

  • msgctl — inspect or delete the queue, including the IPC_RMID that causes a blocked msgrcv to return EIDRM

  • unpack — split the returned frame into type and payload with l! a*

  • IPC::SysV — source of the IPC_NOWAIT, MSG_NOERROR, and related flag constants

  • IPC::Msg — object-oriented wrapper that hides the pack/unpack dance behind a rcv method