\
Linux::Event::Fork
Minimal async child spawning on top of Linux::Event.
This is a policy-layer distribution: it keeps Linux::Event core pristine, and
builds child spawning using only public primitives:
$loop->watch(...)for pipes (stdout/stderr/stdin)$loop->pid(...)for exit observation$loop->after(...)for timeouts
Design goals
- No supervision semantics: no restarts, backoff, or retry policy.
- No framework behavior: explicit callbacks and explicit teardown.
- Drain-first:
on_exitfires only after the child has exited and captured pipes reach EOF. - Low hot-path noise: chunk delivery is raw bytes, no implicit parsing.
Quick start
use v5.36;
use Linux::Event;
use Linux::Event::Fork; # installs $loop->fork
my $loop = Linux::Event->new;
$loop->fork(
tag => "demo",
cmd => [ $^X, '-we', 'print "hi\n"; exit 0' ],
on_stdout => sub ($child, $chunk) {
print "[stdout] $chunk";
},
on_exit => sub ($child, $exit) {
say "exit=" . ($exit->exited ? $exit->code : 'n/a');
$loop->stop;
},
);
$loop->run;
Callback contracts
on_stdout => sub ($child, $chunk) { ... }on_stderr => sub ($child, $chunk) { ... }on_exit => sub ($child, $exit) { ... }where$exitis aLinux::Event::Fork::Exit
$chunk is a raw byte string from sysread() and is not line oriented.
If you want lines/messages, buffer and split in user code.
Spawn forms
Exactly one of:
cmd
cmd => [ $program, @argv ]
Uses exec. If exec fails, the child exits 127 and writes a short message to stderr.
child
child => sub {
exec "myprogram", "arg1";
}
Runs Perl in the child after stdio plumbing and setup options. If it throws or returns, the child exits 127 and writes a short message to stderr.
Stdin
One-shot stdin bytes
stdin => $bytes
Creates a pipe, writes the bytes, and closes stdin.
Streaming stdin with backpressure
stdin_pipe => 1
Creates a pipe and keeps it open; you can stream:
$child->stdin_write($bytes);
$child->close_stdin;
Fork ignores SIGPIPE during writes and treats EPIPE as a normal close condition.
Minimal timeout
timeout => 2.5,
on_timeout => sub ($child) {
warn "timed out: " . ($child->tag // $child->pid);
},
When the timer fires and the child is still running:
- calls
on_timeout(if provided) - sends
TERMto the child once
No escalation to KILL, no restarts.
Output capture controls
By default, a pipe is only created if its callback is provided.
Override with:
capture_stdout => 1|0capture_stderr => 1|0
If you enable capture without a callback, Fork drains the pipe and discards output so the child cannot block on a full pipe.
Setup options (child-side)
Applied in the child after stdio plumbing and before exec/callback:
cwd => "/path"umask => 027env => { KEY => "value" }(overlays onto inherited%ENV)clear_env => 1(start from empty%ENVbefore overlay)
Metadata
tag => $labelfor identity/loggingdata => $opaquefor an arbitrary user payload
Both are available on the returned handle (Linux::Event::Fork::Child).
Stress tests
See examples/README.md for the 90/91 stress scripts and environment controls.
License
Same terms as Perl itself.