thebananamancan
thebananamancan

Reputation: 91

ForkManager SIGINT only kills current process in fork

I want to have all child processes die when I kill a perl process that is using ForkManager. In the code below, if I run it and hit ctrl+c while the sleep line is running, the sleep process is killed, but the print lines are then all simultaneously executed before the script ends. Ideally, I'd like an interrupt to immediately stop all execution. What can I do?

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
    my $fork1 = new Parallel::ForkManager(8);
    while (1) {
        $fork1->start and next;
        system("sleep 15s");
        print "Still going!"
        $fork1->finish;
    }
    fork1->wait_all_children;
}

Upvotes: 3

Views: 730

Answers (2)

Hunter McMillen
Hunter McMillen

Reputation: 61540

According to perldoc system, system actually ignores both SIGINT and SIGQUIT:

Since SIGINT and SIGQUIT are ignored during the execution of system, if you expect your program to terminate on receipt of these signals you will need to arrange to do so yourself based on the return value.

So if you want your processes to stop executing if you SIGINT during the system call, you need to implement that logic yourself:

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
   my $fork1 = new Parallel::ForkManager(8);
   while (1) {
      $fork1->start and next;
      print "Sleeping...";
      system("sleep 15s") == 0 or exit($?);
      print "Still going!";
      $fork1->finish;
   }
   fork1->wait_all_children;
}

OR the more reasonable approach is the use the Perl built-in sleep:

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
   my $fork1 = new Parallel::ForkManager(8);
   while (1) {
      $fork1->start and next;
      print "Sleeping...";
      sleep 15;
      print "Still going!";
      $fork1->finish;
   }
   fork1->wait_all_children;
}

Upvotes: 6

Sobrique
Sobrique

Reputation: 53498

First off - using system means you might have something strange happen, because ... then you're allowing whatever you're calling to do stuff to handle signals by itself.

That may be your problem.

However otherwise, what you can do with perl is configure signal handlers - what to do if a signal is recieved by this process. By default - signals are either set to 'exit' or 'ignore'.

You can see what this is currently via print Dumper \%SIG;

However the simplest solution to you problem I think, would be to set a handler to trap SIGINT and then send a kill to your current process group.

The behavior of kill when a PROCESS number is zero or negative depends on the operating system. For example, on POSIX-conforming systems, zero will signal the current process group, -1 will signal all processes, and any other negative PROCESS number will act as a negative signal number and kill the entire process group specified.

$SIG{'INT'} = sub { 
    kill ( 'TERM', -$$ );
};

Upvotes: 2

Related Questions