| Signals-XSIG documentation | view source | Contained in the Signals-XSIG distribution. |
Signals::XSIG - install multiple signal handlers through %XSIG
Version 0.11
use Signals::XSIG q{:all};
# drop-in replacement for regular signal handling through %SIG
$SIG{TERM} = \&my_sigterm_handler;
$SIG{USR1} = sub { ... };
$SIG{PIPE} = 'DEFAULT';
# %XSIG interface to installing multiple signal handlers
$SIG{TERM} = \&handle_sigterm; # same as $XSIG{TERM}[0] = ...
$XSIG{TERM}[3] = \&posthandle_sigterm;
$XSIG{TERM}[-1] = \&prehandle_sigterm;
# SIGTERM calls prehandle_sigterm, handle_sigterm, posthandle_sigterm
# in that order.
# array operations allowed on @{$XSIG{signal}}
push @{$XSIG{__WARN__}}, \&log_warnings;
unshift @{$XSIG{__WARN__}}, \&remotely_log_warnings;
warn "This warning invokes both handlers";
shift @{$XSIG{__WARN__}};
warn "This warning only invokes the 'log_warnings' handler";
Perl provides the magic global hash variable %SIG to make it
easy to trap and handle signals (see "%SIG" in perlvar and
perlipc (perlipc)).
The hash-of-lists variable %XSIG provided by this module
has a similar interface for setting an arbitrary number of
handlers on any signal.
There are at least a couple of use cases for this module:
You have written a module that raises signals and makes
use of signal handlers, but you don't want to preclude the
end-user of your module from doing their own handling of that
signal. The solution is to install your own signal handler
into a "non-default" index. Now your module's end-user can
set and unset $SIG{signal} as much as he or she would like.
When the signal is trapped, both your module's signal handler
and the end-user's signal handler (if any) will be invoked.
package My::Module::With::USR1::Handler;
use Signals::XSIG;
sub import {
...
# use $XSIG{USR1}, not $SIG{USR1}, in case the user of
# this module also wants to install a SIGUSR1 handler.
# Execute our handler BEFORE any user's handler.
$XSIG{'USR1'}[-1] = \&My_USR1_handler;
...
}
sub My_USR1_handler { ... }
sub My_sub_that_raises_SIGUSR1 { ... }
...
1;
You have multiple "layers" of signal handlers that you want to enable and disable at will. For example, you may want to enable some handlers to write logging information about signals received.
use Signals::XSIG;
# log all warning messages
$XSIG{__WARN__}[1] = \&log_messages;
do_some_stuff();
# now enable extra logging -- warn will invoke both functions now
$XSIG{__WARN__}[2] = \&log_messages_with_authority;
do_some_more_stuff();
# done with that block. disable extra layer of logging
$XSIG{__WARN__}[2] = undef;
# continue, &log_warnings will still be called at next warn statement
Extended signal handling is provided by making assignments to and performing
other operations on the hash-of-lists %XSIG, which is imported into
the calling namespace by default.
A signal handler is one of the following or any scalar variable
that contains one of the following:
DEFAULT
IGNORE
undef
''
unqualified_sub_name # qualified to main::unqualified_sub_name
qualified::sub_name
\&subroutine_ref
sub { anonymous sub }
*unqualified_glob # qualified to *CallingPackage::unqualified_glob
*qualified::glob
(the last two handler specifications cannot be used with Perl 5.8 due to a limitation with assigning globs to tied hashes. See "BUGS AND LIMITATIONS").
There are several ways to enable additional handlers on a signal.
Sets a single signal handler for the given signal.
Identical behavior to the conventional $SIG{signal} = handler
expression. Installs the specified signal handler as the "main"
signal handler. If you are using this module because you don't
want your signal handlers to trample on the signal handlers of
your users, then you generally don't want to use this
expression.
Installs the given signal handler at the specified indicies. When multiple signal handlers are installed and a signal is trapped, the signal handlers are invoked in order from lowest indexed to highest indexed.
For example, this code:
$XSIG{USR1}[-2] = sub { print "J" };
$XSIG{USR1}[-1] = sub { print "A" };
$XSIG{USR1}[1] = sub { print "H" };
$SIG{USR1} = sub { print "P" }; # $SIG{USR1} is alias for $XSIG{USR1}[0]
kill 'USR1', $$;
should output the string JAPH. If a "main" signal handler is
installed, then use this expression with a negative index to
register a handler to run before the main handler, and with a
positive index for a handler to run after the main handler.
A signal handler at a specific slot can be removed by assigining
undef or '' (the empty string) to that slot.
$XSIG{USR1}[1] = undef;
Installs multiple handlers for a signal in a single expression. Equivalent to
$XSIG{signal} = []; # clear all signal handlers
$XSIG{signal}[0] = handler1;
$XSIG{signal}[1] = handler2;
...
All the handlers for a signal can be uninstalled with a single expression like
$XSIG{signal} = [];
@{XSIG{signal}} = ();
Installs additional signal handlers to be invoked after
all currently installed signal handlers. There is a
corresponding pop operation, but it cannot be used to
remove the main handler or any prior handlers.
$XSIG{USR1} = [];
$XSIG{USR1}[-1] = \&prehandler;
$XSIG{USR1}[0] = \&main_handler;
$XSIG{USR1}[1] = \&posthandler;
push @{$XSIG{USR1}}, \&another_posthandler;
pop @{$XSIG{USR1}}; # removes \&another_posthandler
pop @{$XSIG{USR1}}; # removes \&posthandler
pop @{$XSIG{USR1}}; # no effect - pop doesn't remove index <= 0
Analagous to push, installs additional signal handlers
to be invoked before all currently installed signal handlers.
The corresponding shift operation cannot be used to remove
the main handler or any later handlers.
$XSIG{USR1} = [ $h1, $h2, $h3, $h4 ];
$XSIG{USR1}[-1] = $j1;
$XSIG{USR1}[-3] = $j3;
unshift @{$XSIG{USR1}}, $j4; # installed at $XSIG{USR1}[-4]
shift @{$XSIG{USR1}}; # removes $j4
shift @{$XSIG{USR1}}; # removes $j3
shift @{$XSIG{USR1}}; # removes $XSIG{USR1}[-2], which is undef
shift @{$XSIG{USR1}}; # removes $j1
shift @{$XSIG{USR1}}; # no effect - shift doesn't remove index >= 0
The %XSIG extended signal handler hash is exported into
the calling namespace by default.
None
If the main handler for a signal ($XSIG{signal}[0]) is set to DEFAULT,
that handler will be ignored if there are any other handlers installed
for that signal. This is DWIM.
For example, this will invoke the default behavior for SIGUSR1:
$SIG{USR1} = 'DEFAULT';
kill 'USR1', $$;
but this will not
$SIG{USR1} = 'DEFAULT';
$XSIG{USR1}[1] = \&do_something_else;
kill 'USR1', $$;
This will also invoke the default behavior for SIGTERM (probably terminating
the program) since it is not the main handler that is the DEFAULT handler:
$SIG{TERM} = \&trap_sigterm;
$XSIG{TERM}[-1] = 'DEFAULT';
kill 'TERM', $$;
If the DEFAULT handler is installed more than once, the default
behavior for that signal will only be invoked once when
that signal is trapped.
Marty O'Brien, <mob at cpan.org>
local %SIGThis module converts %SIG into a tied hash. As documented in
the perltie "BUGS" section ("BUGS" in perltie),
localizing a tied hash will cause the old data
not to be restored when the local version of the hash goes out of scope.
Avoid doing this:
{
local %SIG;
...
}
or using modules and functions which localize %SIG
(fortunately, there are not that many examples of code that
use this construction
[http://www.google.com/codesearch?hl=en&lr=&q=%22local+%25SIG%22+lang:perl&sbtn=Search]).
Should you identify a code block that localizes %SIG and you can't/don't
want to avoid using it, the workaround is to save and restore %SIG at
the end of the local scope:
use Signals::XSIG;
...
my %temp = %SIG;
function_call_or_block_that_localizes_SIG();
%SIG = %temp;
In addition, the behavior of the tied %SIG while it is local'ized
is different in different versions of Perl, and all of the features
of Signals::XSIG might or might not work while a local copy
of %SIG is in use.
Note that it is perfectly fine to localize an element of %SIG:
{
local $SIG{TERM} = ...; # this is ok.
something_that_might_raise_SIGTERM();
} # end of local scope, $SIG{TERM} restored.
"%SIG" in perlvar specifies that you can assign a signal handler with the construction
$SIG{signal} = *foo; # same as ... = \&__PACKAGE__::foo
It turns out that in Perl 5.8, this causes a fatal error when
you use this type of assignment to a tied hash. This is a limitation
of tied hashes in Perl 5.8, not a problem with the magic of %SIG.
Signals::XSIG adds some overhead to signal processing
and that could ultimately make your signal processing
less stable as each signal takes longer to process.
This module may not be suitable for applications where
many signals need to be processed in a short time.
This module hangs its hat on a lot of the same hooks
that the Perl debugger needs to use. As you step through
code in the debugger, you may often find yourself
stepping through the code in this module (say, where
some core module is installing a $SIG{__WARN__}
handler. You may find this annoying.
Please report any bugs or feature requests to
bug-signal-handler-super at rt.cpan.org, or through the web interface at
http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Signals-XSIG.
I will be notified, and then you'll automatically be notified of
progress on your bug as I make changes.
You can find documentation for this module with the perldoc command.
perldoc Signals::XSIG
You can also look for information at:
Copyright 2010-2011 Marty O'Brien.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
| Signals-XSIG documentation | view source | Contained in the Signals-XSIG distribution. |