First of all, this is cool stuff ... thanks for posting.

The problem you are having (from what I can tell) is a extremely subtle one. Your program is working almost as designed, but there are a few issues. First you are not printing enough characters to cause the print buffer to actually print to the screen. So all of your characters are getting pushed into the buffer, then they over write each other in the last instant because the buffer is not getting flushed during the execution of the program. So to fix this problem add:local $| = 1 inside the do loop. $| is the 'autoflush' variable. 'local' will prevent the global $| from being overwritten in case you need buffered output elsewhere in your program.

The next issue is that your waitpid is actually hanging ... waiting for th child to die. You want to keep looping, so you need to change the second paramater to 64 or POSIX::WNOHANG
use POSIX; ... code here ... $child_pid = waitpid(-1, WNOHANG);
This prevents the waitpid from hanging. So for your complete functioning code:
use POSIX; if ($pid = fork) { # parent do { local $| = 1; print "\b-"; sleep 1; print "\b\\"; sleep 1; print "\b|"; sleep 1; print "\b/"; sleep 1; $child_pid = waitpid(-1,WNOHANG); } until $child_pid == -1; } else { # child #exec("cmd"); sleep 15; exit(0); }
The last waitpid was not necessary. I also changed exec "cmd" to sleep 15 for testing.

Now there is one more minor thing I would suggest. You only check for the child death every 4 seconds. You probably should be checking for this constantly with a signal handler and do the waitpid in the signal handler. My signal handler just sets a global flag to tell the parent to stop looping:
use POSIX; $keep_going = 1; #set the SIGCHLD signal handler $SIG{CHLD} = \&REAPER; if ($pid = fork) { # parent while($keep_going) { local $| = 1; print "\b-"; sleep 1; print "\b\\"; sleep 1; print "\b|"; sleep 1; print "\b/"; sleep 1; } } else { # child sleep 15; exit(0); } #SIGCHLD signal handler sub REAPER { #test if all childred are dead unless(waitpid(-1, WNOHANG) == -1 ) { $keep_going = 0; } #reset the signal handler for more than #one child death. $SIG{CHLD} = \&REAPER }
So now REAPER will get called whenever there is a signal from any child, and the waitpid will not have to be staged every 4 seconds.

I hope this helps.

In reply to Re: fork... by perlmonkey
in thread fork... by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.