September 2000
Program interrupt handling is generally a pretty easy topic, especially in languages that have been doing it - literally - for decades (C for example). This article will look at interrupt handling in Perl or rather additional interrupt handling in Perl. First I will cover the whys and why nots and then follow up with some code samples.
The perl interpreter has built in interrupt handling, additionally, the environment one is using a Perl program in most likely has it as well (e.g. a shell). So when I say interrupt handling, I mean additional specialized handling or just nice to know general handling.
For the most part, debugging. A lot of programmers already do interrupt handling or have built in methods to handle errors in the environment such as a web server, but for many command line driven programs, you may wish to trap signals and log them for debugging and troubleshooting purposes. A case where I saw it come in very handy was when I took a look at Jeremy Fischer's program DHCPReg where a little interrupt handling might be helpful. The program gets a variety of different information about DHCP leases. It is command line driven, so, seeing that there might be the possibility of keyboard interrupts or other weirdness, I contributed the idea of using some rudimentary interrupt handling. Jeremy went all out and made a Perl module called Interrupt.pm so he could easily reuse the simple interrupt handlers.
Finally, another good reason to use interrupt handlers (in any program really) is in case there is some cleanup involved such as deleting temporary files, closing open handles etc.
Basically if there is no need or there is another mechanism in place for doing so, a classic example is web servers. Most web servers have built in error handling for cgi program errors and adjustable error logging facilities.
The first thing we need to do is identify the signals we wish to
trap and tell them (should they be trapped) a routine name to use.
For our first example, we will use a sub called - you
guessed it - interrupt:
1. $SIG{'INT' } = 'interrupt'; $SIG{'QUIT'} = 'interrupt';
2. $SIG{'HUP' } = 'interrupt'; $SIG{'TRAP'} = 'interrupt';
3. $SIG{'ABRT'} = 'interrupt'; $SIG{'STOP'} = 'interrupt';
That should be pretty simple, the $SIG{'*'} are
jumping to the
interrupt sub function. So now how about a look at the
actual function:
1. sub interrupt {
2. my($signal)=@_;
3. print "Caught Interrupt\: $signal \n";
4. print "Now Exiting\n";
5. exit(1);
6. }
$signal.Again, pretty simple stuff but very helpful for troubleshooting.
The function, however, does not do much and it could use some help
such as adding the die to it. Let's take it a bit
further and add some better functionality to it, we will assume
here that we have an open file-handle called LOG:
1. sub interrupt {
2. my($signal)=@_;
3. &log("Interrupt: Caught signal $signal exiting\n");
4. &clean_die("Caught signal $signal exiting\n");
5. exit(1);
6.}
$signallog to put some
information about what happened into the log-file (see below).clean_die to take
care of business (see below).Now lets take a look at the called sub functions to see what they do:
1. sub log {
2. local($string)=$_[0];
3. if($log){
4. print LOG &date,": $string\n";
5. return 1;
6. }
7. return 0;
8. }
$string.
1. sub clean_die {
2. my($die_string) = $_[0];
3. &log("Clean_die: $die_string");
4. close(LOG) if ($log);
5. die $die_string;
6. }
$die_stringlog and log the event.dieAs you can see these sub functions are pretty simple and being that it is Perl, very flexible. One could easily make all of these one sub function or get really extravagant with them - that is up to the programmer. You may see something about these examples you don't like or may be incorrect - feel free to roll your own.
Piled on top of just altering the examples I have shown, a completely different approach can be taken for handling interrupt signals, you could use different sub functions for each type of signal for example. Then your initial assignment of them might look something like:
1. $SIG{'INT' } = 'int '; $SIG{'QUIT'} = 'quit';
2. $SIG{'HUP' } = 'hup '; $SIG{'TRAP'} = 'trap';
3. $SIG{'ABRT'} = 'abrt'; $SIG{'STOP'} = 'stop';
Or break them into groups that get handled different etc. - the sky is the limit really. My only word of advice is if you choose to use a method like the ones discussed in this article, try to keep it simple. If all you need is rudimentary handling then I suggest picking up the module mentioned in the beginning of the text.
(based on last 2 months log reports)