--- name: msgsnd signature: 'msgsnd ID, MSG, FLAGS' since: 5.0 status: documented categories: ["SysV IPC"] --- ```{index} single: msgsnd; Perl built-in ``` *[SysV IPC](../perlfunc-by-category)* # 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`](msgget)), and returns true on success or false on error with [`$!`](../perlvar) 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 ```perl msgsnd ID, MSG, FLAGS ``` ## What you get back True on success, false on failure. On failure [`$!`](../perlvar) 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: ```perl 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`](msgrcv) callers use to select which messages to dequeue. The payload follows, uninterpreted. Build the buffer with [`pack`](pack) using the `l!` (native `long`) and `a*` (raw bytes) specifiers: ```perl 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`](msgrcv) and cause `msgsnd(2)` to fail with `EINVAL`. ## Global state it touches - [`$!`](../perlvar) — 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: ```perl 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 [`$!`](../perlvar) if the queue is full, rather than sleeping: ```perl 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`](msgrcv): ```perl 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: ```perl 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`](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`](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`](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`](msgrcv), which *does* taint its output) is where filtering belongs. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`msgget`](msgget) — obtain the queue id passed as `ID`; call this first, or receive the id from whoever created the queue - [`msgrcv`](msgrcv) — the matching receive primitive; its `TYPE` argument selects against the `l!` prefix written here - [`msgctl`](msgctl) — inspect the queue's `msg_qbytes` limit or remove the queue when done - [`pack`](pack) — build the `l! a*` buffer `msgsnd` requires; also the tool for any further structure inside the payload - [`$!`](../perlvar) — carries the `errno` from a failed `msgsnd`; compare against `Errno` constants to branch on specific failures