Processes

setpgrp#

Set the process group of a process.

setpgrp moves the process identified by PID into the process group identified by PGRP. A PID of 0 means the current process; a PGRP of 0 means “use PID as the new group id” — that is, make the process a group leader. With no arguments it defaults to setpgrp(0, 0), which makes the current process the leader of a new process group whose id equals its own pid.

This is the Perl interface to the underlying setpgid(2) / setpgrp(2) system call. It is the building block for detaching a process from its controlling terminal and for job-control schemes that want to send signals to a whole group at once with kill.

Synopsis#

setpgrp PID, PGRP
setpgrp            # same as setpgrp(0, 0)

What you get back#

1 on success, undef on failure with $! set to the reason (commonly EPERM when the target process is not the caller or a child of the caller, or ESRCH when no such process exists). Check the return value — silently proceeding with a process still in the old group is almost never what you want.

setpgrp(0, 0)
    or die "setpgrp failed: $!";

Global state it touches#

  • $! — set to the errno value on failure. Not touched on success.

Examples#

Detach the current process into a new process group of its own. This is the classic first step of a daemonisation sequence, run after fork and before closing the standard handles:

setpgrp(0, 0)
    or die "setpgrp failed: $!";

Move a just-spawned child into its own group so that a SIGTERM sent to the group kills the child and any grandchildren it spawns, without touching the parent:

my $pid = fork // die "fork: $!";
if ($pid == 0) {
    setpgrp(0, 0) or die "setpgrp: $!";
    exec @cmd or die "exec: $!";
}
# parent: signal the whole group with a negative pid
kill 'TERM', -$pid;

Read the group id back after setting it, using getpgrp:

setpgrp(0, 0) or die $!;
my $pgid = getpgrp(0);
print "now leader of group $pgid\n";

Handle the portability failure mode — on a platform without the underlying system call the function raises an exception rather than returning undef:

eval { setpgrp(0, 0) };
if ($@) {
    warn "no process-group support on this platform: $@";
}

Edge cases#

  • No arguments defaults to (0, 0). Writing setpgrp; is the same as setpgrp(0, 0) — make the current process a new group leader. The no-argument form is the portable form (see below).

  • BSD 4.2 compatibility. The historical BSD 4.2 setpgrp took no arguments. Scripts that must run on such systems can only rely on the setpgrp(0, 0) / setpgrp() forms; any other argument combination is non-portable.

  • Raises, not returns undef, on unsupported platforms. On a machine that implements neither POSIX setpgid(2) nor BSD setpgrp(2), setpgrp raises an exception. This is the one failure mode that does not go through $! — wrap in eval if you need to degrade gracefully.

  • EPERM on cross-session moves. The kernel rejects attempts to move a process into a group in a different session, or to move a process that has already called exec. Catch $! == EPERM and fall back rather than retrying.

  • Signalling the whole group. Once a group is established, kill SIG, -$pgid delivers SIG to every process in the group. The negative-pid convention is a property of kill, not of setpgrp — but it’s the reason you usually call setpgrp in the first place.

  • Not a session leader. setpgrp changes process group, not session. To detach from the controlling terminal entirely you need POSIX::setsid, which creates a new session and a new group in one step.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • getpgrp — read the current process group id; the obvious companion for verifying a setpgrp call took effect

  • POSIX::setpgid — the POSIX-named wrapper around the same system call, preferred in new code because its argument order and semantics are unambiguous across platforms

  • POSIX::setsid — create a new session and a new process group in one call; use this, not setpgrp, for full terminal detachment

  • fork — the call that almost always precedes setpgrp; a child that wants its own group calls setpgrp(0, 0) right after fork returns 0

  • kill — how you actually use a process group once you’ve built one: kill SIG, -$pgid signals every member