SysV IPC

shmget#

Create or look up a System V shared memory segment and return its identifier.

shmget is the allocation step for SysV shared memory. Given a numeric KEY (either IPC_PRIVATE for a fresh anonymous segment or a well-known number agreed with other processes), a requested SIZE in bytes, and a bit-mask of FLAGS (creation flags OR’d with a 9-bit mode), it returns a kernel-assigned integer identifier. That identifier — the shmid — is what every subsequent call (shmctl, shmread, shmwrite) uses to refer to the segment. The segment persists in the kernel until it is explicitly removed with shmctl($shmid, IPC_RMID, 0) or the system reboots; closing the creating process does not release it.

Synopsis#

shmget KEY, SIZE, FLAGS

What you get back#

An integer shared-memory identifier (shmid) on success, suitable for passing to shmctl, shmread, and shmwrite. On failure returns a false value and sets $! to the underlying errno.

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

my $shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | S_IRUSR | S_IWUSR)
    or die "shmget: $!";

The returned identifier is an opaque small integer. Do not do arithmetic on it, do not compare it to 0 for truth — the identifier 0 is a legitimate value on some systems. Always check the return against the documented failure sentinel (see Differences from upstream).

Global state it touches#

  • $! — set on failure to the underlying errno: EACCES (permissions), EEXIST (segment for that key already exists and both IPC_CREAT and IPC_EXCL were given), EINVAL (SIZE below SHMMIN or above SHMMAX, or SIZE differs from the existing segment when looking one up), ENFILE / ENOSPC (kernel segment-table full), ENOENT (no segment for that key and IPC_CREAT was not given), ENOMEM (insufficient memory).

The function is otherwise pure with respect to Perl-visible state: no special variables beyond $! are touched, $_ is not read.

Examples#

Create a fresh private segment — the usual pattern when parent and children share memory via fork:

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

my $size  = 4096;
my $shmid = shmget(IPC_PRIVATE, $size, IPC_CREAT | S_IRUSR | S_IWUSR)
    or die "shmget: $!";
# children inherit $shmid across fork and attach via shmread/shmwrite

Attach to a pre-existing segment by its well-known key. SIZE and mode bits are ignored in this form; pass 0 for both:

my $key   = 0xDEADBEEF;
my $shmid = shmget($key, 0, 0)
    or die "shmget: $!";

Create-or-open with IPC_CREAT. If the key already exists the existing shmid is returned; otherwise a new segment of SIZE bytes is created with the given mode:

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

my $shmid = shmget(0x1234, 8192, IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP)
    or die "shmget: $!";

Fail if a segment already exists, using IPC_EXCL. This is the safe pattern for a process that wants to be the unique creator:

use IPC::SysV qw(IPC_CREAT IPC_EXCL S_IRUSR S_IWUSR);
use Errno qw(EEXIST);

my $shmid = shmget(0x1234, 4096, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
if (!$shmid) {
    die "shmget: $!" unless $! == EEXIST;
    # another process won the race; fall back to plain lookup
    $shmid = shmget(0x1234, 0, 0) or die "shmget (lookup): $!";
}

Full create-use-destroy cycle with guaranteed cleanup via END:

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

my $shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | S_IRUSR | S_IWUSR)
    or die "shmget: $!";

END {
    shmctl($shmid, IPC_RMID, 0) if defined $shmid;
}

shmwrite($shmid, "hello", 0, 5)  or die "shmwrite: $!";
shmread($shmid, my $buf, 0, 5)   or die "shmread: $!";

Edge cases#

  • use IPC::SysV is effectively mandatory. The flag constants (IPC_PRIVATE, IPC_CREAT, IPC_EXCL, IPC_RMID) and mode bits (S_IRUSR, S_IWUSR, S_IRGRP, …) are not built-ins. Without the import you end up passing bare barewords that stringify to 0 and silently do the wrong thing.

  • Key 0 is not IPC_PRIVATE. IPC_PRIVATE is defined as 0 on Linux, but passing a literal 0 with no IPC_CREAT asks the kernel for the segment at key 0, which is the IPC_PRIVATE sentinel and yields EINVAL. Import the constant by name and use it.

  • SIZE is rounded up to a page boundary by the kernel; the returned segment may be larger than requested. Ask the kernel for the effective size with shmctl($shmid, IPC_STAT, $ds) and unpack the shmid_ds structure if you need the real number.

  • Segment persists beyond process exit. A crashed or killed creator leaves the segment in the kernel. Use ipcs -m to list orphaned segments and ipcrm -m <shmid> to remove them. Install an END block or a signal handler to call shmctl IPC_RMID on shutdown.

  • IPC_RMID is deferred, not immediate. It marks the segment for destruction; actual removal happens once the attach count drops to zero. Safe to call right after shmget if you know no one else will attach.

  • Kernel limits. SHMMNI caps the total number of segments system-wide (/proc/sys/kernel/shmmni). SHMMAX caps the size of one segment (/proc/sys/kernel/shmmax). On a shared host these are easy to hit; treat ENOSPC and EINVAL-from-large-size as configuration issues, not bugs.

  • SysV IPC is not available on every platform. Upstream Perl built on a system without HAS_SHM dies with "System V IPC is not implemented on this machine". pperl targets Linux only, where SysV IPC is always present, so the call is always dispatched.

Differences from upstream#

  • Returns -1 rather than undef on failure. Both values are false under Perl’s truth rules, so the idiomatic shmget(...) or die "$!" works unchanged, but code that distinguishes “not an identifier” via defined $shmid will read -1 as defined. Prefer checking for truth, or compare against -1 explicitly when you want to branch on the failure sentinel. The -1 is the raw shmget(2) return value, which is the documented error sentinel for that syscall.

See also#

  • shmctl — control operations on the segment shmget returned; use IPC_RMID to delete it, IPC_STAT to inspect size and permissions

  • shmread — read SIZE bytes from the segment into a Perl scalar

  • shmwrite — write a Perl scalar into the segment at an offset

  • msgget — the equivalent allocation step for SysV message queues when you want a queue, not a flat buffer

  • semget — the equivalent for SysV semaphores when the goal is synchronisation rather than shared data

  • IPC::SysV — source of the IPC_* and S_* flag constants shmget requires; no local reference page, see upstream POD