| FuguLib::Process(3p) | Perl Library Manual | FuguLib::Process(3p) |
NAME
FuguLib::Process —
spawn, supervise and reap child processes
SYNOPSIS
use FuguLib::Process;
my $result = FuguLib::Process->spawn_command(
cmd => [ '/usr/local/bin/mydaemon', '-f' ],
daemonize => 1,
stdout => '/var/log/mydaemon.log',
check_alive => 2,
);
FuguLib::Process->terminate($result->{pid}) if $result->{success};
DESCRIPTION
FuguLib::Process covers the parts of
running a child process that are easy to get wrong: telling a child that
started from one that exited immediately, escalating from
SIGTERM to SIGKILL on a
schedule, and reaping zombies without blocking.
The module keeps no state; every method is a class method.
spawn_command
spawn_command(%args)
forks, redirects the standard descriptors, and executes a command.
The arguments are as follows:
- cmd
- Array reference holding the command and its arguments. Required, and must not be empty.
- daemonize
- If true, the child calls setsid(2) before exec. The default is false.
- stdin, stdout, stderr
- Paths for the child's standard descriptors. Each defaults to /dev/null.
- check_alive
- Seconds to wait before confirming the child survived. The default is 1; 0 skips the check and returns as soon as the fork succeeds.
- on_success
- Code reference called with the child's process ID once the spawn is judged successful.
- on_error
- Code reference called with a message when the spawn fails.
When check_alive is non-zero the parent sleeps for that many seconds and then makes two tests: a non-blocking waitpid(2), which reaps the child and proves it exited, and kill(2) with signal 0, which proves it is still there. This is what catches an exec that failed for a reason the fork could not report, such as a command that does not exist.
is_alive
is_alive($pid)
reports whether a process exists and is not a zombie. A zombie child is
reaped as a side effect of the check and then reported as not alive.
terminate
terminate($pid,
%args) sends SIGTERM, waits,
and sends SIGKILL if that was not enough.
The arguments are as follows:
- grace_period
- Seconds to wait between the two signals. The default is 5.
- on_kill
- Code reference called once the process is gone.
reap
reap($pid)
reaps one zombie child without blocking.
reap_all
reap_all() reaps every zombie child that
is ready, without blocking, and returns how many there were.
wait_exit
wait_exit($pid,
$timeout) polls until the process exits or the timeout
expires. $timeout defaults to 30 seconds.
spawn_perl
spawn_perl(%args)
runs Perl code in a child process, passing through the
-I paths the parent picked up from
-I, use lib or
PERL5LIB, so the child sees the same modules.
code is the program
text and args an array reference of arguments for it;
every other argument is handed to
spawn_command().
RETURN VALUES
spawn_command() and
spawn_perl() return a hash reference. On success it
holds success set to 1 and pid.
On failure success is 0 and
error describes what went wrong;
pid and exit_code are also
present when the child was reached and died.
is_alive() returns 1 or 0.
terminate() returns 1 if the process is
gone, 0 if it survived SIGKILL.
reap() returns 1 if the child was reaped
or was never there, 0 if it is still running.
reap_all() returns a count.
wait_exit() returns 1 if the process
exited within the timeout, 0 otherwise.
EXAMPLES
Run a helper and stop it again:
my $r = FuguLib::Process->spawn_command(
cmd => [ 'mdnsctl', 'publish', $name, '_hap', 'tcp', $port ],
on_error => sub ($err) { $log->err('mdnsctl: %s', $err) },
);
FuguLib::Process->terminate($r->{pid}, grace_period => 10)
if $r->{success};
ERRORS
No method dies. Failures are reported through the returned hash reference or the boolean return value, and through on_error when one was supplied.
SEE ALSO
kill(2), setsid(2), waitpid(2), FuguLib::Log(3p), FuguLib::State(3p)
AUTHORS
Dick Olsson <hi@senzilla.io>
CAVEATS
spawn_command() blocks the caller for
check_alive seconds. The check is a plain
sleep(3), so a
program that spawns several children pays for each one in turn.
A child that legitimately finishes inside the check_alive window is reported as a failure, with an error saying it completed immediately and an exit_code of 0. Use check_alive set to 0 for commands that are expected to be short.
is_alive() and
reap() call
waitpid(2), which
only ever reaps children of the calling process. For any other process they
fall back to kill(2)
with signal 0, which cannot distinguish a live process from a zombie.
Process IDs are recycled. Nothing here can tell the process that was asked about from a later one that inherited its number.
| July 27, 2026 | OpenBSD |