blahblah has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I'm having troubles deciphering exactly what is going on in some fork open pipe code, despite reading perlopentut and perlipc slowly and repeatedly. I have stripped out as much as I can and added some comment-questions:
open(P, "|-") or # fork a process using fh # P as STDIN to the child. do { # huh? Why would open P fail... # and we launch child?!? open(STDERR,">&=$err"); # alias STDERR to output # to the $err filehandle open(STDOUT,">&=$out"); # alias STDOUT to output # to the $out filehandle exec(@cmd); # run command. How to # capture @cmd errors gracefully? exit 9 # what is 9's special # meaning here? }; close($err); close($out); print P "test input to child" or die ("Mein Leiben! $!"); close(P) or die("Stella! $!");

Admittedly, I'm most puzzled by the "open or do". I find that a very strange way to fork open a child process. Since this subroutine is called many times, how might the open fail and prompt the opening of the child? I would expect the open to be mandatory - AND - the do to be mandatory. Urg.

Thank you very much for your time and help.

Thanks!

Replies are listed 'Best First'.
Re: Forked pipe open...or do???
by Skeeve (Parson) on Sep 12, 2006 at 07:33 UTC
    I think this excertp from perlipc explains it a bit better than what you have:
    use English '-no_match_vars'; my $sleep_count = 0; do { $pid = open(KID_TO_WRITE, "|-"); unless (defined $pid) { warn "cannot fork: $!"; die "bailing out" if $sleep_count++ > 6; sleep 10; } } until defined $pid;
    update: Just forgot.... You already read it... So here is a bit of explanation. The "open" returns a process ID, 0 or undef.
    undef
    We are out of processes. This is when open fails
    0
    This is the child process... The "or" part of your open. But it would be reached for undef too!
    pid
    This is for the parent process to have a pid to wait for.

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
Re: Forked pipe open...or do???
by shmem (Chancellor) on Sep 12, 2006 at 09:44 UTC

    Where did you get that funny piece of code from?

    Without context, it's hard to guess why it was written that way.

    open(P, "|-") does an implicit fork. If that fails, its mostly due to hitting some limit (user limit or process table full). If the process limit is hit, the only way to execute another process is via exec - it substitutes the current process with the new process. exec never returns (since perl is gone if exec succeeds). If the exec fails, the code snippet exits 9 - let's take a guess at that number:

    qwurx [shmem] ~> perl -le 'print "$_: ",$! = $_ for 8..10' 8: Exec format error 9: Bad file descriptor 10: No child processes

    So, this code

    • forks and opens a pipe to the child
    • if that fails, it dups STDOUT and STDERR without checking if the open succeeds - why?
    • it execs, and failing that, it's assumed that the filehandle dups didn't work?

    Tss...

    • what is in @cmd?
    • the close($err); should be close($err) or warn "close: $!\n" - what happens if you run it like this?

    I'd ask the author to explain what he meant to do, and that done, rewrite.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Forked pipe open...or do???
by sgifford (Prior) on Sep 12, 2006 at 15:45 UTC
    The key point, which Skeeve has alluded to, is that this form of open returns the same value as fork, that is to say, it returns twice: once in the child with the value 0, and again in the parent with the PID of the child. So the part in the do is executed in the child process, and the parent process skips the do and executes the rest of the program.

    This is a confusing and unreliable way of writing the code; it handles errors incorrectly, and uses an idiom normally reserved for error handling in a surprising way. When you feel you understand it well, you might want to rewrite it in a more straightforward and robust way.