in reply to fork...

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.