ealeon
ealeon

Reputation: 12460

perl: can end block be called when program is 'kill'

BEGIN {
    while (1) {
        print "hi\n";
    }
}


END {
    print "end is called\n";
}

in shell:

kill <pid>

OUTPUT:

hi
hi
hi
hi
hi
hi
hi
hi
hi
Terminated

The end block didnt get called when i killed it via kill or ctrl-c.

Is there something equivalent that will always get called before program exits

Upvotes: 1

Views: 1185

Answers (2)

Sobrique
Sobrique

Reputation: 53508

Ctrl C sends a SIGINT to your program. You can 'catch' this with a signal handler by setting the appropriate entry in %SIG. I would note - I don't see why you're using BEGIN that way. BEGIN is a special code block that's called at compile time - at the very first opportunity. That means it's triggered when you run perl -c to validate your code, and as such is really a bad idea to set as an infinite loop. See: perlmod

E.g.

#!/usr/bin/perl

use strict;
use warnings;

$SIG{'INT'} = \&handle_kill; 
my $finished = 0; 

sub handle_kill {
     print "Caught a kill signal\n";
     $finished++; 
}


while ( not $finished ) {
    print "Not finished yet\n";
    sleep 1;
}

END {
    print "end is called\n";
}

But there's a drawback - some signals you can't trap in this way. See perlipc for more details.

Some signals can be neither trapped nor ignored, such as the KILL and STOP (but not the TSTP) signals. Note that ignoring signals makes them disappear. If you only want them blocked temporarily without them getting lost you'll have to use POSIX' sigprocmask.

By default if you send a kill, then it'll send a SIGTERM. So you may want to override this handler too. However it's typically considered bad to do anything other than exit gracefully with a SIGTERM - it's more acceptable to 'do something' and resume when trapping SIGHUP (Hangup) and SIGINT.

You should note that Perl does 'safe signals' though - and so some system calls won't be interrupted, perl will wait for it to return before processing the signal. That's because bad things can happen if you abort certain operations (like close on a file where you're flushing data might leave it corrupt). Usually that's not a problem, but it's something to be aware of.

Upvotes: 6

Miguel Prz
Miguel Prz

Reputation: 13792

put the proper signal handler in your code:

$SIG{INT} = sub { die "Caught a sigint $!" };

the control-c sends the SIGINT signal to the script, who is catched by this handler

Upvotes: 5

Related Questions