SyncExec(3pm)

πŸ“¦
version 1.01 Β· 5 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

✨ NAME ✨

Proc::SyncExec β€” spawn processes but actually tell you when exec() flops, bestie πŸ’…


🌸 SYNOPSIS 🌸

# Normal-looking piped opens which properly report exec() errors in $!:
sync_open WRITER_FH, "|command -with args" or die $!;
sync_open READER_FH, "command -with args|" or die $!;

# Synchronized fork/exec which reports exec errors in $!:
$pid = sync_exec $command, @arg;
$pid = sync_exec $code_ref, $cmd, @arg;     # run code after fork in kid

# fork() which retries if it fails, then croaks() if it still fails.
$pid = fork_retry;
$pid = fork_retry 100;              # retry 100 times rather than 5
$pid = fork_retry 100, 2;           # sleep 2 rather than 5 seconds between

# A couple of interfaces similar to sync_open() but which let you
# avoid the shell:
$pid = sync_fhpopen_noshell READERFH, 'r', @command;
$pid = sync_fhpopen_noshell WRITERFH, 'w', @command;
$fh = sync_popen_noshell 'r', @command_which_outputs;
$fh = sync_popen_noshell 'w', @command_which_inputs;
($fh, $pid) = sync_popen_noshell 'r', @command_which_outputs;
($fh, $pid)= sync_popen_noshell 'w', @command_which_inputs;

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so here's the whole vibe: this module is a lil collection of functions for synchronized process spawning with full error return. The ✨magic✨ is that if the kid's exec() call totally faceplants, the reason it failed gets reported right back to the parent. No mystery silence. No ghost failures. Periodt. πŸ’–

Fair warning though: these functions will croak() at you if they hit an unexpected system error β€” think a pipe() failure, or a fork() that keeps failing over and over 😭. It's giving "we're not ignoring that, we're screaming about it."

And listen β€” nothing is exported by default. You gotta ask for what you want, no cap. πŸ™ˆ


πŸŽ€ fork_retry [max-retries [sleep-between]]

This one just runs fork() over and over until it succeeds, or until it's made max-retries attempts (default is 5, iykyk). Between each attempt it takes a lil nap for sleep-between seconds (default is 5).

And if the very last fork() still fails? fork_retry croak()s. Like, we tried, we really did πŸ’€


🧚 sync_exec [code] command...

Basically a fork()/exec() sequence, but with a couple of plot twists, bestie.

First twist: sync_exec does not return until after the fork()ed child has already performed its exec(). That synchronization is lowkey useful in some unusual circumstances. Main character timing energy. ⏰

Second: normally you get the pid of the child process back. But if the child fails its exec(), sync_exec returns undef and sets $! to the reason the kid's exec() died. So you always know what went down. 🫢

Now, because the @cmd array gets passed directly to Perl's exec(), Perl might decide to invoke the command via the shell β€” this happens if @cmd contains only one element and it looks like it needs a shell to interpret it. And if that happens? The return value of sync_exec only tells you whether the exec() of the shell worked. Not the command. Just the shell. Slight oopsie in the vibes department. 😬

There's also an optional initial code argument that has to be a code reference. If you pass it, it runs in the child right before exec() is called β€” perfect for setting up redirections or whatever else you're up to. ✨ But if code returns false, no exec happens at all. Instead you get a failure returned using the current $! value (or EINTR if $! is 0). Noted, bestie. πŸ“

Heads up! If the fork() fails, or if there's any other unexpected system error, sync_exec croak()s rather than returning. 🚨

🌈 sync_fhpopen_noshell fh type cmd [arg]...

It's a popen(), but it never invokes the shell and it uses sync_exec() under the covers. See "sync_exec" for the deets up above. πŸ‘†

The type is either 'r' to read from the process, or 'w' to write to it. Pick your fave. πŸ’–

You get back the pid of the forked process. That's the whole return value, slay.


πŸ”₯ sync_popen_noshell type cmd arg...

Same energy as sync_fhpopen_noshell, except you don't have to supply the filehandle yourself. Convenient!! πŸ‘‘

Context matters here, so pay attention:

  • In an array context, the return value is a list made of the filehandle and the PID of the child. (($fh, $pid) β€” iconic duo. 🫢)
  • In a scalar context, only the filehandle comes back.

πŸ’œ sync_open fh [open-spec]

This is like a regular Perl open(), except that if a pipe is involved and the implied exec() fails, sync_open() fails too, with $! set appropriately. See "sync_exec". βœ…

And just like sync_exec, sync_open will croak() if there's an unexpected system error (like a pipe() that flops). 🚨

Also also β€” same rule as sync_exec: if you use a command that Perl needs the shell to interpret, you'll only ever know whether the exec of the shell worked. If you want to be sure that doesn't happen, use sync_fhpopen_noshell or sync_exec instead. No shell, no drama. πŸ’…


πŸ‘‘ AUTHOR πŸ‘‘

Roderick Schertler <roderick@argon.org>


⭐ SEE ALSO ⭐

perl(1).


And that's the whole page, bestie β€” brought to you by perl v5.36.0, dated 2022-10-13, and filed under SyncExec(3pm) in the User Contributed Perl Documentation. Go spawn some processes responsibly, ily. πŸŽ€βœ¨

πŸ“¦ where this page comes from