Little Black Lights

mommy, look, over there!

ElCondor

[aka Martin Schipany]

Preface

Black Lights?

  • 'When you try and operate one of these weird black controls which are labeled in black on a black background, a small black light lights up black to tell you that you've done it'



    Zaphod Beeblebrox

  • Signals are always there, telling you that or even what happened, and that it might as well be just a good idea to take some action on this. But it's up to you to do so. And you are free to fail with style
  • What are signals (good for)?

    Types of Signals

    examples most commonly used signals

    How to send/Issue Signals

    How To Process Signals

    %SIG: code in that hash will be automatically processed in case the corresponding signal is triggered

    How to use that?

    Let's take a look at some examples:

    Enemy of the commandline

    We just want to take CTRL-C it's power, nothing fancy

    Whom the Bell tolls

    We have a task that might take forever, but we want to limit the time it may take.

    Who wants to live forever

    Time and again, every good program is going to die. Gathering more information should be the goal. or even more ...

    Controlling a Daemon

    We start a program to be run in the background. Let's assume is has some important job to to, that may not be interrupted without saving the current state. Furthermore we want it to write out some data when we tell it to.

    Spawn ..

    We need a bunch of processes, so let's fork some children:
    $SIG{CHLD} = \&reaper;
    if ( $pid = fork() ) {
        push @children,$pid; # remember
        return $pid;
    }
    elsif ( defined $pid ) {
        &write_pidfile($pid)
        $SIG{TERM} = \&do_clean_shutdown();
        $SIG{HUP}  = \&reload_config();
        $SIG{CHLD} = 'IGNORE';
        &run_main();
    }
    else { croak "fork failed: $!" }

    .. Watch ..

    We can check our children from time to time, how they are:
    foreach my $child(@children) {
        if (kill 0 => $child ) {
            print "Child $pid is well and alive\n";
        }
    }
    
    Or can remove apparent heirs :
    foreach my $child(@children) {
        print "Removing $pid from binary gen-pool\n";
        kill 'TERM' => $child;
        # maybe wait for the reaper?
    }
    

    ... and Reap

    We setup a routine that is called in case a child dies:
    use POSIX ":sys_wait_h";
    sub reaper {
        my $pid;
        while (($pid = waitpid(-1, WNOHANG)) > 0) {
            my $status=$?;
            $log_sys->info( "child $pid gone: $status");
            if (!$running) {
                unlink_pidfile($pid); # cleanup
            } else {
                fork_new();
            }
            $SIG{CHLD} = \&reaper;
        }
    }

    Slippery when wet

    Signals (no matter if handled) are shiny .. or not. here some (ancient) code to retry open if it failed due to an occured interrupt:
    my $maxtry=10;
    do {
      $err = open($fh, '<', $locked_file);
      $errstr = $!;
      $maxtry--;
    } while ($errstr eq "Interrupted system call"
            && $maxtry);

    Caveats

    Signal handling has some caveats, more or less serious depending on what you need, expect, or where you run your code.

    plus lucis

    Perls internal safe signal handling can be bypassed

    Signals with Flags

    Resources

    Grey Lights?

    Remember: mommy told you to look both ways before crossing the street!
    And she was right: there might always be something to hit you in the back!


    Thank you!