NAME
Linux::Event::Kernel::Process - pidfd process lifecycle and asynchronous stdio
SYNOPSIS
package Worker;
use parent 'Linux::Event::Kernel::Process';
sub on_stdout ($process, $bytes) {
print $bytes;
}
sub on_exit ($process) {
say 'exit code: ' . $process->exit_code
if defined $process->exit_code;
$process->loop->stop;
}
package main;
my $worker = $loop->add(Worker->spawn(
command => ['/usr/bin/example', '--once'],
stdout => 'pipe',
stderr => 'pipe',
));
DESCRIPTION
Linux::Event::Kernel::Process is the public process leaf. One object combines process creation or observation, pidfd identity-safe lifecycle notification, optional asynchronous stdin/stdout/stderr, decoded exit status, and pidfd-based signaling.
Linux::Event uses posix_spawnp for spawned children and never runs Perl code in a post-fork child. pidfd operations avoid directing signals or lifecycle state at an unrelated process after numeric PID reuse.
SPAWNING
spawn accepts a command argument vector and does not insert a shell:
my $process = Worker->spawn(
loop => $loop, # optional
command => ['/usr/bin/make', '-j4'], # required
cwd => '/srv/project', # optional
env => { BUILD_MODE => 'test' }, # optional replacement env
stdin => 'pipe', # optional
stdout => 'pipe', # optional
stderr => 'pipe', # optional
data => $state, # optional
);
Construction is side-effect free while detached. The child is created when the object attaches through loop => $loop or $loop->add($process). Consequently pid is undefined before attachment.
env replaces the complete environment when supplied; omit it to inherit the current environment. Use an explicit shell in command only when shell syntax is intentionally required.
STANDARD I/O
Each stdio option accepts inherit, pipe, null, or a caller filehandle. stderr may additionally be stdout to merge child stderr into child stdout.
Pipe callbacks are:
sub on_stdout ($process, $bytes) { ... }
sub on_stdout_eof ($process) { ... }
sub on_stderr ($process, $bytes) { ... }
sub on_stderr_eof ($process) { ... }
sub on_stdin_drain ($process) { ... }
Readable child pipes are drained by the native process I/O helper while preserving read_size callback chunking and max_reads_per_tick fairness.
write_stdin($bytes) writes immediately when possible and queues the remainder. High/low watermarks provide cooperative flow control and max_pending_stdin can impose a hard safety bound. close_stdin drains already accepted input, then closes the child's input pipe to deliver EOF.
OBSERVING AN EXISTING PROCESS
An existing PID may be observed instead of spawned:
my $process = Worker->new(
pid => $pid,
reap => 1,
);
$loop->add($process);
reap => 1 is the default and requires a child process whose status this object owns. reap => 0 permits lifecycle notification for a non-child but leaves decoded wait-status fields undefined.
EXIT CALLBACK AND STATUS
A concrete subclass defines on_exit($process). When a reaped child exits, Linux::Event records either exit_code or term_signal, plus the core-dump flag and conventional raw wait status. Remaining available stdout/stderr bytes are drained before on_exit.
The Loop remains available during on_exit and is released after callback completion. Callback exceptions propagate after native cleanup.
SIGNALS
signal($number) uses pidfd_send_signal rather than a bare numeric PID and returns the Process object. Failures are structured Linux::Event::Error values.
There is deliberately no generic cancel. Stopping observation, closing stdin, asking a child to terminate, and confirming process exit are distinct operations. Applications choose an explicit signal and continue running the Loop until on_exit confirms lifecycle completion.
ERRORS AND OWNERSHIP
Optional on_error($process, $error) receives asynchronous process or stdio failures. Without it Linux::Event warns and retains last_error.
The Loop retains a running Process. Destroying the Loop closes Linux::Event resources but does not secretly kill the child. Spawned processes and observed children with reap => 1 exclusively own their wait status; do not also use a competing waitpid or SIGCHLD reaper for the same child.
PLATFORM
Process requires Linux pidfd support and build headers for pidfd_open and pidfd_send_signal. The runtime lifecycle/status path targets Linux 5.4 or newer. The build also requires libc support for posix_spawn_file_actions_addchdir_np.
SEE ALSO
Linux::Event::Loop, docs/PROCESS-DESIGN.md.