semctl#
Perform a control operation on a System V semaphore set.
semctl is the Perl-level binding for the semctl(2) system call. It
reads or modifies the state of the semaphore set identified by ID —
getting or setting a single semaphore’s value, fetching or installing
the full value vector, reading the associated semid_ds metadata, or
removing the set entirely. CMD selects the operation; SEMNUM
selects which semaphore within the set (ignored for set-wide commands
like IPC_STAT, IPC_RMID, GETALL, SETALL); ARG is the command’s
input or output buffer.
semctl is a thin wrapper — the semantics, the command constants, and
the shape of ARG all come straight from the C-level call. You will
almost always want:
use IPC::SysV;
first, to pull in the IPC_STAT, IPC_RMID, GETVAL, SETVAL,
GETALL, SETALL, GETPID, GETNCNT, GETZCNT constants.
Synopsis#
semctl $id, $semnum, $cmd, $arg
semctl $id, 0, IPC_RMID, 0 # destroy set
semctl $id, $n, SETVAL, $value # set one
semctl $id, 0, SETALL, $packed # set all
What you get back#
Return follows the same convention as ioctl:
The string
"0 but true"when the underlying call returned0— this string is false numerically (so it prints0in numeric context) but true in boolean context, letting you distinguish success-with-zero from failure in one test.The actual integer return value otherwise.
The idiomatic test is therefore:
my $rc = semctl($id, $n, GETVAL, 0);
defined $rc or die "semctl: $!";
Check defined, not truth — a legitimately zero semaphore value would
fail a plain if ($rc).
For CMD values that read data into ARG (IPC_STAT, GETALL),
ARG must be a modifiable lvalue (a plain variable, not a literal
or expression); on success the buffer is overwritten in place with the
returned bytes and you unpack it yourself.
Global state it touches#
Sets $! on failure. No other interpreter globals
involved.
Examples#
Read a single semaphore’s current value:
use IPC::SysV qw(GETVAL);
my $value = semctl($id, $semnum, GETVAL, 0);
defined $value or die "GETVAL: $!";
Set a single semaphore:
use IPC::SysV qw(SETVAL);
semctl($id, $semnum, SETVAL, 1)
or die "SETVAL: $!";
Read all semaphore values at once. The buffer has to be pre-allocated
to the right size — nsems native shorts — before the call. pack
with an unused count is the usual way:
use IPC::SysV qw(GETALL);
my $nsems = 4;
my $buf = pack("s!*", (0) x $nsems); # allocate room
semctl($id, 0, GETALL, $buf) or die $!;
my @vals = unpack("s!*", $buf);
Install a full set of values:
use IPC::SysV qw(SETALL);
my $buf = pack("s!*", 1, 0, 0, 1);
semctl($id, 0, SETALL, $buf)
or die "SETALL: $!";
Fetch the semid_ds structure for the set. ARG is written in place
with the packed struct; its layout is platform-specific, so unpack
with the help of IPC::Semaphore rather than by hand unless you
have to:
use IPC::SysV qw(IPC_STAT);
my $ds = "";
semctl($id, 0, IPC_STAT, $ds)
or die "IPC_STAT: $!";
Destroy the semaphore set. SEMNUM and ARG are unused; pass 0:
use IPC::SysV qw(IPC_RMID);
semctl($id, 0, IPC_RMID, 0)
or die "IPC_RMID: $!";
Edge cases#
ARGmust be a real variable for read commands.GETALLandIPC_STATwrite intoARG; passing a literal (semctl($id, 0, GETALL, "")) or a read-only expression is a runtime error. The variable’s existing contents are overwritten, not appended to.ARGmust be pre-sized. The kernel writes exactlynsems * sizeof(short)bytes forGETALL, orsizeof(struct semid_ds)forIPC_STAT. Passing a shorter buffer is undefined behaviour in the underlying C call;pack("s!*", (0) x $nsems)is the standard idiom forGETALL.Native
short, not portableshort. Semaphore values are Cshort(signed, typically 16-bit). Uses!inpack/unpack— the!picks the platform-native type. Plainsforces little-endian 16-bit and will produce wrong results on big-endian or LP64-short systems."0 but true"returns.GETVALon a semaphore whose value is0,GETPID/GETNCNT/GETZCNTreturning zero, and other zero-valued successes all return the literal string"0 but true". Arithmetic contexts see0; boolean contexts see true. Usedefinedto check for failure.SEMNUMis ignored for set-wide commands.IPC_STAT,IPC_RMID,SETALL,GETALLact on the whole set. Pass0by convention; passing any other value is harmless but obscures intent.After
IPC_RMIDthe id is invalid. Every subsequentsemctlorsemopon$idfails withEINVAL/EIDRM. Do not cache the id past removal.The set is kernel-global and persists across process exits. A set created by a crashed script remains until someone calls
IPC_RMID(or the system reboots). Useipcs -s/ipcrm -sfrom the shell to inspect or clean up leaked sets.Permissions come from
semget. TheIPC_CREAT | modepassed at creation time controls who may issue whichsemctlcommands.EACCESfromsemctlmeans the mode bits disallow the requested operation for the current effective uid.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
semget— create or look up the semaphore set whose id you then pass tosemctlsemop— the actual wait / signal operations;semctlis for control and inspection,semopdoes the workmsgctl— the analogous control call for System V message queues; same return-value conventionshmctl— the analogous control call for System V shared memory; same return-value conventionpack— how to build theARGbuffer withs!for semaphore values and thesemid_dsstructIPC::Semaphore— object wrapper that hidessemctlbehind named methods; reach for it when a script does more than one or two calls