Colin Wood
Colin Wood

Reputation: 467

Perl: Why does this create thousdands of child processes?

So when I run this code it seems to fork bomb the system can you guys help me out? All I want to do is start a thread for each one of the appWatch domains and enviroments.

#!/usr/bin/perl
#
#
#       Starts the mass processes to watch each directory & enviroment.
#
#
#
###################################################################################
use strict;
use warnings;
use POSIX 'setsid';
setsid();
my @domains = (qw(austin batman luke heman drevil joker skeltor drevil goodguy badguy));
my @envs = (qw(qa dev));
        foreach my $env (@envs){
                foreach my $guy (@domains){
                        unless(my $pid = fork()){
                                system("echo $env.$guy");
                                system("sleep 10 ");
                                #system("./appWatch -d $guy -e $env");
                                open PID, ">>pid.lock";
                                print PID $$ . "\n";
                                print "$$ is Parent, $pid is child";
                }
        }
}
                wait();

Upvotes: 2

Views: 397

Answers (2)

Chas. Owens
Chas. Owens

Reputation: 64939

Your code should only create three children. If you are seeing a bunch of children being created then you are running different code (or the culprit is appWatch not your code). On a slightly unrelated note, there are a couple things you should probably be doing differently:

  1. fork has three possible return values, not two
  2. you must reap your children or set the system up to reap them for you
  3. you should use exec instead of system if you don't want to return to the code
  4. you should use the multiple argument version of system and exec instead of the one argument version if you don't want the shell to do stuff with the arguments.

Here is my version of your code:

$SIG{CHLD}  = "IGNORE"; #auto-reap the children
my @domains = qw(domains);
my @envs    = qw(enviromentA enviromentB);
for my $env (@envs){
        for my $guy (@domains){
                die "could not fork: $!" unless defined(my $pid = fork);
                next if $pid;
                exec "./appWatch", "-d", $guy, "-e", $env;
                die "exec must have failed";
        }
}

You updated version of the code shows what happened. Your child does not exit. Here is how I would write your code:

#!/usr/bin/perl
# Starts the mass processes to watch each directory & enviroment.

use strict;
use warnings;
use POSIX 'setsid';
setsid();

my @domains = qw(
    austin  batman luke    heman
    drevil  joker  skeltor drevil
    goodguy badguy
);
my @envs = qw(qa dev);

my @pids;
for my $env (@envs){
    for my $guy (@domains){
        die "could not fork: $!" unless defined(my $pid = fork);
        if ($pid) {
            push @pids, $pid;
            next;
        }
        print "$env.$guy\n";
        sleep 10; #FIXME: I don't know if you really need this
        #exec will replace the child process with appWatch
        exec "./appWatch", "-d", $guy, "-e", $env;
        die "exec failed for some reason";
    }
}
for my $pid (@pids) {
    waitpid $pid, 0;
}

Upvotes: 3

Greg Bacon
Greg Bacon

Reputation: 139691

With

$ cat appWatch 
#! /usr/bin/perl -l
print "[", join("][" => @ARGV), "]";

running on

$ uname -a
Linux mybox 2.6.32-24-generic #39-Ubuntu SMP Wed Jul 28 05:14:15 UTC 2010 x86_64 GNU/Linux

I get no fork bomb, just an unexciting Cartesian product:

$ ./prog.pl 
[-d][domains][-e][enviromentA]
[-d][domains][-e][enviromentB]

Upvotes: 1

Related Questions