Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I kill Perl 'system' calls when the main script is killed?

Tags:

kill

perl

Pervious answers to this questions have focused on forks:

  • kill background process when shell script exit
  • How to make child process die after parent exits?
  • Are child processes created with fork() automatically killed when the parent is killed?

For this question, I'm just asking about calls to the 'system' function.

Say I have a script called sleep.pl:

use strict;
use warnings;
sleep(300);

I then have a script called kill.pl

use strict;
use warnings;
system("sleep.pl");

I run kill.pl and using ps I find the process id of kill.pl and kill it (not using kill -9, just normal kill)

sleep.pl is still sleeping.

I imagine the solution to my question involves a SIG handler, but what do I need to put into the handler to kill the child process?

like image 803
mmccoo Avatar asked Apr 22 '09 23:04

mmccoo


People also ask

How do I kill a running Perl script?

In the ssh window where it is running you can often just hit ctrl+c to kill it however there are some instances where that will not work. The kill command would be the next step.


3 Answers

Use setsid to make your process the new group leader. Then you can send a kill to the group ID and kill all processes that belong to the group. All processes that you spawn from the leader process inherit the group ID and belong to your newly created group. So sending a kill to the group will kill them all. The only tricky thing is in order to be able to use setsid you must close your standard in and output, as that is a requirement for setsid.

like image 70
lothar Avatar answered Oct 01 '22 10:10

lothar


use strict;
use warnings;
setpgrp $$, 0;
system("sleep.pl");
END {kill 15, -$$}

But if you need this approach you do something wrong. You should not do this. Run and kill your kill process in right way instead.

$ perl -e 'system("sleep 100")' &
[1] 11928
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
11928 pts/1    S      0:00  \_ perl -e system("sleep 100")
11929 pts/1    S      0:00  |   \_ sleep 100
11936 pts/1    R+     0:00  \_ ps f
$ kill %1
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
11949 pts/1    R+     0:00  \_ ps f

How it works? Shell (bash in mine case) should set your process as group leader if you run on background. Then if you use kill %? syntax shell kills group in right way. Compare this:

$ perl -e 'system("sleep 100")' &
[1] 12109
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
12109 pts/1    S      0:00  \_ perl -e system("sleep 100")
12113 pts/1    S      0:00  |   \_ sleep 100
12114 pts/1    R+     0:00  \_ ps f
$ kill 12109
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
12124 pts/1    R+     0:00  \_ ps f
12113 pts/1    S      0:00 sleep 100

But kill %? works in this way:

$ perl -e 'system("sleep 100")' &
[1] 12126
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Rs     0:01 /bin/bash
12126 pts/1    S      0:00  \_ perl -e system("sleep 100")
12127 pts/1    S      0:00  |   \_ sleep 100
12128 pts/1    R+     0:00  \_ ps f
$ kill -12126
[1]+  Terminated              perl -e 'system("sleep 100")'
$ ps f
  PID TTY      STAT   TIME COMMAND
 4564 pts/1    Ss     0:01 /bin/bash
12130 pts/1    R+     0:00  \_ ps f
like image 40
Hynek -Pichi- Vychodil Avatar answered Oct 01 '22 08:10

Hynek -Pichi- Vychodil


Your question really is a specific instance of the more general "how to ensure a child dies when the parent dies" question. There's just no getting around that. There's nothing really special about system(); it just forks a child process and waits for it to exit.

system() is roughly this:

sub system 
{
    my $kidpid = fork;
    if ( $kidpid )
    {
        waitpid $kidpid; 
          # parent process blocks here waiting for the child process to return
    }
    else
    {
        exec( @_ );
    }
}

Killing the process group is about your only option.

like image 39
Rob K Avatar answered Oct 01 '22 10:10

Rob K