Hello all, I'm looking for pointers about troubleshooting perlfork on Win32.

My app is a pretty run of the mill tcp listening daemon. The master process fork() a worker process to deal with an incoming request and gets back to waiting for incoming requests.

The worker process forks again to create a 'probe' process (ie running an external process to get it's return code and output). We fork to a second level to manage timeouts and kill() the probe process if it takes too long.

The IPC method used between the worker and the probe is pipe().

So the master spawns many workers, each worker spawns a probe.

Now here's where I start to hit trouble. If I only get one request, everything is fine. If I get many requests at once, sometime it works, sometimes it doesn't. Frequently, it looks like the different worker processes are blocking on the read operation on the pipe.. When it does work, everything comes back when the longest probe process comes back. When it doesn't work, everything simply hangs and the whole process must be killed.

For example, if I get two requests where one probe in the end sleep(1) and the other sleep(5), either it hangs, or I get both results after 5 seconds.

This is under activestate build 819 (perl 5.8.8) on winxp.

I have read the perlfork page. I know the fork emulation is rather experimental. It does mention in the known issues that if you use pipes 'you need to be very cautious' -- **but** it doesn't give any more details than that! I'm looking for more info.. either my design is wrong, or its a bug (and of course a bug is possible if the whole thing is experimental)..

Any pointers appreciated.. At the end of the mail is my test script.. it's not the full app, only the fork() parts to reproduce the behavior.. Call the main script with a single number as argument for the number of Worker process you want to spawn in the loop.

The 'plugin' script called from the probe process is simple:

#--------------------- cut here ----------------------------
print "\n        +++I'm plugin. called with $ARGV[0]";
sleep($ARGV[0]);
print "\n        +++yay!";
#--------------------- cut here ----------------------------

main script:

#--------------------- cut here ----------------------------

#####
# MAIN
#####

print "MASTER[$$] start of the file\n";

foreach(1..$ARGV[0]) {
  mastersub();
}
print "MASTER[$$] ended\n";


#####
# SUBS
#####

sub mastersub {

  my $pid = fork;

  if (!defined($pid)) { # fork error
    print "MASTER[$$] couldn't fork!\n";
    exit -1;

  } elsif ($pid) { # code to continue running as master
    print "MASTER[$$] Spawned Worker: $pid\n"

  } else { # code to run in the new thread/fork
    print "   Worker[$$] just forked, calling sub\n";
    workersub(); 
    print "   Worker[$$] ending\n";
    exit;
  }
}

sub workersub {
  print "   Worker[$$] creating pipe\n";
  pipe(RH,WH);
 
  my $old_fh = select (WH);
  $| = 1;           # autoflush TRUE
  select($old_fh);  # restore default handle
 
  $cpid = fork;
 
    if(!defined($cpid)) { # fork error
      print "   Worker[$$] couldn't spawn child\n";
      exit -1;

    } elsif ($cpid) { # worker process waiting for info from probe
      print "   Worker[$$] wont write\n";
      close WH or print "   close prob in $$";

      print "   Worker[$$] spawned probe: $cpid ".
            scalar localtime()."\n";

      my @res = <RH>;
      print "   Worker[$$] read from probe at ".
            scalar localtime().
            "\n   [EMAIL PROTECTED]   =======\n";
   
   
    } else { # slave child calls plugin and returns output via pipe
      print "      probe[$$] wont read\n";
      close RH or print "      b1 close prob in $$";
     
      my $old_fh = select (WH);
      $| = 1;            # autoflush TRUE
       select($old_fh);  # restore default handle

      print "      probe[$$] started!\n";
      my $rnd = int(rand(5));
      print "      probe[$$] calling plugin with $rnd\n";
      print WH "      probe[$$] here's your output: " .
               `perl plugin.pl $rnd`;
      print "      probe[$$] ending.\n";
      close WH or print "      b2 close prob in $$";
      exit
    } # end of the probe/plugin calling code

   close RH or print "   close prob ending $$"; # Worker ends, close handle
}
#--------------------- cut here ----------------------------
_______________________________________________
ActivePerl mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to