Brad Fitzpatrick (bradfitz) wrote in lj_dev,
Brad Fitzpatrick
bradfitz
lj_dev

stacking signal handlers

I spent a good portion of my evening tracing down the fact that ljlib.pl's $SIG{'HUP'} was blowing away BML's HUP handler. It shouldn't have taken so long to find, but I was thinking BML's namespace cleanup code was doing it.

So ... I need a good way to allow multiple signal handlers.

BML registers its first:

$SIG{'HUP'} = sub {
    $HUP_COUNT++;
    reset_caches();
};

sub reset_caches
{
    %FileModTime = ();
    %Config = ();
    %FileBlockData = (); 
    %FileBlockFlags = (); 
}
Later ljlib.pl is included from lj-bml-init.pl:
## we want to set this right away, so when we get a HUP signal later
## and our signal handler sets it to true, perl doesn't need to malloc,
## since malloc may not be thread-safe and we could core dump.
## see LJ::clear_caches and LJ::handle_caches
$LJ::CLEAR_CACHES = 0;

## if this library is used in a BML page, we don't want to destroy BML's
## HUP signal handler.
if ($SIG{'HUP'}) {
    my $oldsig = $SIG{'HUP'};
    $SIG{'HUP'} = sub {
	&{$oldsig};
	&LJ::clear_caches;
    };
} else {
    $SIG{'HUP'} = \&LJ::clear_caches;    
}

# called from a HUP signal handler, so intentionally very very simple
# so we don't core dump on a system without reentrant libraries.
sub clear_caches
{
    $LJ::CLEAR_CACHES = 1;
}

# handle_caches
# clears caches, if the CLEAR_CACHES flag is set from an earlier HUP signal.
# always returns trues, so you can use it in a conjunction of statements
# in a while loop around the application like:
#        while (LJ::handle_caches() && FCGI::accept())
sub handle_caches
{
    return 1 unless ($LJ::CLEAR_CACHES);
    $LJ::CLEAR_CACHES = 0;

    %LJ::CACHE_STYLE = ();
    %LJ::CACHE_PROPS = ();
    $LJ::CACHED_MOODS = 0;
    $LJ::CACHED_MOOD_MAX = 0;
    %LJ::CACHE_MOODS = ();
    %LJ::CACHE_MOOD_THEME = ();
    %LJ::CACHE_USERID = ();
    %LJ::CACHE_USERNAME = ();
    %LJ::CACHE_USERPIC_SIZE = ();
    %LJ::CACHE_CODES = ();
    %LJ::CACHE_USERPROP = ();  # {$prop}->{ 'upropid' => ... , 'indexed' => 0|1 };
    return 1;
}

The new hack is in bold. Proposals for a better way?

The only problem with this is that if ljlib.pl is included more than once, its signal handler is added to the list extra times. But since we're removing all "require 'ljlib.pl'" lines from the code, this isn't a problem, really.

Comments?

Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 9 comments