#!/usr/bin/perl -w

# This script is intended to illustrate the effect of various signals
# Cameron Hayne, June 2003 

use strict;

my $delay = 1;
my $count = 0;

# function that gets called upon quit
sub finish()
{
    print "Cleaning up, please wait ...\n";
    for (1 .. 5)
    {
	print ".\n";
	sleep 1;
    }
    print "Finished cleaning up, now exiting\n\n";
    exit;
}

# Signal Handlers:
# These functions get invoked when the script receives the corresponding signal
# Note: signal numbers are in /usr/include/sys/signal.h

sub handle_SIGHUP()  # number 1
{
    print "\nReceived HUP signal\n";
    print "Resetting state\n\n";
    $delay = 1;
    $count = 0;
}

sub handle_SIGINT()  # number 2
{
    print "\nReceived INT signal\n";
    print "Do it again to get the default action\n\n";
    $SIG{INT} = 'DEFAULT';
}

sub handle_SIGQUIT()  # number 3
{
    print "\nReceived QUIT signal\n";
    print "But I'm not going to do anything about it!\n\n";
}

sub handle_SIGABRT()  # number 6
{
    print "\nReceived ABRT signal\n";
    print "But I'm not going to do anything about it!\n\n";
}

sub handle_SIGKILL()  # number 9, number 9, number 9, ...
{
    # this will never happen - KILL cannot be caught !
    print "\nReceived KILL signal\n";
}

sub handle_SIGTERM()  # number 15
{
    print "\nReceived TERM signal\n";
    print "Do it again to get the default action\n\n";
    $SIG{TERM} = 'DEFAULT';
}

sub handle_SIGSTOP()  # number 17
{
    # this will never happen - STOP cannot be caught !
    print "\nReceived STOP signal\n";
}

sub handle_SIGUSR1()  # number 30
{
    print "\nReceived USR1 signal\n";
    print "Changing delay\n\n";
    $delay = 1 if ++$delay > 3;;
}

sub setup_signals()
{
    $SIG{HUP}  = \&handle_SIGHUP;   #  1
    $SIG{INT}  = \&handle_SIGINT;   #  2
    $SIG{QUIT} = \&handle_SIGQUIT;  #  3
    $SIG{ABRT} = \&handle_SIGABRT;  #  6
    $SIG{KILL} = \&handle_SIGKILL;  #  9
    $SIG{TERM} = \&handle_SIGTERM;  # 15
    $SIG{STOP} = \&handle_SIGSTOP;  # 17
    $SIG{USR1} = \&handle_SIGUSR1;  # 30
}

sub setup_input()
{
    use Fcntl;

    # We want non-blocking input (so the script doesn't wait for input)
    # Note that it might be necessary to call this again if STDIN got reset
    # by the shell (e.g. after a STOP signal)

    my $flags = 0;
    fcntl(STDIN, F_GETFL, \$flags)
	or die "Couldn't get flags for STDIN : $!\n";

    $flags |= O_NONBLOCK;
    fcntl(STDIN, F_SETFL, $flags)
	or die "Couldn't set flags for STDIN: $!\n";
}

sub check_for_quit()
{
    my $input;

    if (read(STDIN, $input, 1))
    {
	return 1 if lc($input) eq 'q';
    }
    return 0;
}


# -- MAIN --

setup_signals();
setup_input();

print "\nWelcome to the 'testsignals' script\n";
print "The PID of this script is $$\n";
print "Try sending it various signals via the 'kill' command\n";
print "from another window. (E.g. kill -1 $$)\n";
print "Signals: HUP = 1, INT = 2, QUIT = 3, KILL = 9\n"; 
print "         TERM = 15, STOP = 17, USR1 = 30\n"; 
print "Also try keyboard actions like control-C, control-Z, control-\\\n";
print "\n";

while (1)
{
    ++$count;
    print "Working $count (Type q followed by Return to quit)\n";
    if (check_for_quit())
    {
	print "Okay, I'm quitting now\n";
	finish();
    }
    sleep $delay;
}
print "How did we get here? (Shouldn't ever happen)\n";
exit;

