SysV IPC

msgctl#

Perform a control operation on a System V IPC message queue.

msgctl is a direct wrapper around the C msgctl(2) system call. It inspects, modifies, or removes the message queue identified by ID. The operation selected by CMD determines how ARG is used — either as an input descriptor, an output buffer, or ignored entirely. The symbolic constants needed for CMD (IPC_STAT, IPC_SET, IPC_RMID, and on Linux IPC_INFO, MSG_STAT, MSG_INFO) live in IPC::SysV, which you have to pull in before the names resolve.

Synopsis#

use IPC::SysV;

msgctl $id, IPC_STAT, $buf       # read queue info into $buf
msgctl $id, IPC_SET,  $buf       # write queue info from $buf
msgctl $id, IPC_RMID, 0          # destroy the queue

What you get back#

Return value follows the same convention as ioctl:

  • undef on error, with $! set.

  • The string "0 but true" when the underlying call returned 0. This is the zero-valued success case — it tests true in boolean context and compares equal to 0 in numeric context, so one check handles both success and failure.

  • The raw non-zero integer return otherwise (for example the index returned by Linux-specific MSG_STAT).

The "0 but true" convention exists precisely so that msgctl(...) or die does the right thing even when the syscall legitimately returns zero:

msgctl $id, IPC_RMID, 0
    or die "msgctl IPC_RMID failed: $!";

How ARG is used#

ARG plays three different roles depending on CMD. The kernel only touches the memory in the directions the command requires:

  • IPC_STATARG must be a writable scalar. The kernel fills it with the packed msqid_ds structure describing the queue (permissions, owner, last-send/last-receive times, queue byte limits, counts). Unpack with IPC::SysV helpers rather than hand-rolling the layout; msqid_ds varies across kernels and libc versions.

  • IPC_SETARG must contain a packed msqid_ds produced by a prior IPC_STAT on the same (or compatible) queue. Only a few fields are honoured: msg_perm.uid, msg_perm.gid, msg_perm.mode (low 9 bits), and msg_qbytes. The rest is ignored.

  • IPC_RMIDARG is unused. Pass 0. The queue is marked for destruction; any blocked msgsnd / msgrcv on it fails with EIDRM.

On Linux only, MSG_STAT and MSG_INFO also accept a writable scalar for ARG and return extra data; these are non-portable and should be gated behind a runtime check.

Global state it touches#

  • $! — set on failure with the system errno (EPERM, EACCES, EINVAL, EIDRM, EFAULT are the common values).

  • No other special variables are touched.

Examples#

Read the queue header and inspect the current byte limit:

use IPC::SysV qw(IPC_STAT);

my $buf = "";
msgctl($id, IPC_STAT, $buf)
    or die "msgctl IPC_STAT failed: $!";

# Layout is platform-dependent; use IPC::SysV helpers to decode.

Shrink the queue’s byte budget. Round-trip through IPC_STAT so the immutable fields keep their current kernel values:

use IPC::SysV qw(IPC_STAT IPC_SET);

my $buf = "";
msgctl($id, IPC_STAT, $buf) or die "stat: $!";
# ... modify msg_qbytes inside $buf via IPC::SysV ...
msgctl($id, IPC_SET,  $buf) or die "set: $!";

Destroy a queue when done. ARG is ignored, but it still has to be passed — 0 is the conventional placeholder:

use IPC::SysV qw(IPC_RMID);

msgctl($qid, IPC_RMID, 0)
    or warn "could not remove queue $qid: $!";

Idiomatic success test that works for the "0 but true" case:

my $rc = msgctl($id, IPC_RMID, 0);
die "msgctl failed: $!" unless defined $rc;   # undef = error
# $rc is now either "0 but true" or a positive integer

Edge cases#

  • IPC::SysV not loaded: bare constant names like IPC_STAT become barewords and, under use strict, a compile-time error. Always use IPC::SysV first.

  • Scalar passed to IPC_STAT is not writable: croaks with Modification of a read-only value attempted. Use a plain my $buf = "" — not a constant, not a string literal.

  • Length mismatch on IPC_SET: if ARG is shorter than the kernel’s msqid_ds, the call fails with EFAULT. Always start from an IPC_STAT buffer rather than packing one from scratch.

  • Removed queue (EIDRM): once IPC_RMID has been issued, any further operation on the same ID fails with $! set to EIDRM, not EINVAL. Scripts that poll a queue must treat EIDRM as “queue is gone, stop.”

  • Permission errors: IPC_SET and IPC_RMID require effective UID match or CAP_SYS_ADMIN. Kernel returns EPERM, not EACCES, for ownership failures.

  • Return-value trap: if (msgctl(...) == 0) is wrong — on success the value is the string "0 but true", which stringifies as non-empty but compares numerically equal to 0. Test with defined for the error case, or rely on or die.

  • Platform availability: System V IPC is not universal. On systems where the kernel omits it, msgctl raises the runtime exception msgctl not implemented.

Differences from upstream#

Fully compatible with upstream Perl 5.42 on Linux. System V IPC is the only supported IPC surface; pperl targets Linux, so the portability caveats that upstream perlport lists for non-Linux platforms do not apply.

See also#

  • msgget — obtain the queue ID that msgctl operates on

  • msgsnd — send a message to the queue

  • msgrcv — receive a message from the queue

  • semctl — the semaphore-set analogue, same return convention and same IPC_STAT / IPC_SET / IPC_RMID pattern

  • shmctl — the shared-memory-segment analogue

  • IPC::SysV — the constants (IPC_STAT, IPC_SET, IPC_RMID) and the msqid_ds pack/unpack helpers this call requires