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 theerrnofrom the failed syscall whenmsgsndreturns 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
0or a negative type fails withEINVAL. The type-selection semantics inmsgrcvreserve those values for selector logic.Message exceeds
msg_qbytes. IfMSGis larger than the queue’s configured per-message limit,msgsndfails withEINVALregardless ofFLAGS. Check and raise the limit withmsgctlIPC_SETif 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 onEINTRif the signal is expected and benign.Queue full with
IPC_NOWAIT. Fails immediately withEAGAIN. This is the only way to enforce bounded latency on the send side.Missing type prefix. Forgetting to
packthel!type prefix passes the raw payload as-is; the firstsizeof(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.IDis a queue id, not a key. Pass the integer returned bymsgget, not theKEYyou gave tomsgget. Confusing the two yieldsEINVALor, 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
wbit of the queue’s mode for its effective uid/gid). Otherwise the call fails withEACCES.Tainting.
MSGis read as a byte string; no taint checking is performed on it here. IfMSGcame 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 asID; call this first, or receive the id from whoever created the queuemsgrcv— the matching receive primitive; itsTYPEargument selects against thel!prefix written heremsgctl— inspect the queue’smsg_qbyteslimit or remove the queue when donepack— build thel! a*buffermsgsndrequires; also the tool for any further structure inside the payload$!— carries theerrnofrom a failedmsgsnd; compare againstErrnoconstants to branch on specific failures