Async-Interrupt

 view release on metacpan or  search on metacpan

Interrupt.pm  view on Meta::CPAN

=head1 SYNOPSIS

 use Async::Interrupt;

=head1 DESCRIPTION

This module implements a single feature only of interest to advanced perl
modules, namely asynchronous interruptions (think "UNIX signals", which
are very similar).

Sometimes, modules wish to run code asynchronously (in another thread,
or from a signal handler), and then signal the perl interpreter on
certain events. One common way is to write some data to a pipe and use an
event handling toolkit to watch for I/O events. Another way is to send
a signal. Those methods are slow, and in the case of a pipe, also not
asynchronous - it won't interrupt a running perl interpreter.

This module implements asynchronous notifications that enable you to
signal running perl code from another thread, asynchronously, and
sometimes even without using a single syscall.

=head2 USAGE SCENARIOS

=over 4

=item Race-free signal handling

There seems to be no way to do race-free signal handling in perl: to
catch a signal, you have to execute Perl code, and between entering the
interpreter C<select> function (or other blocking functions) and executing
the select syscall is a small but relevant timespan during which signals
will be queued, but perl signal handlers will not be executed and the
blocking syscall will not be interrupted.

You can use this module to bind a signal to a callback while at the same
time activating an event pipe that you can C<select> on, fixing the race
completely.

This can be used to implement the signal handling in event loops,
e.g. L<AnyEvent>, L<POE>, L<IO::Async::Loop> and so on.

=item Background threads want speedy reporting

Assume you want very exact timing, and you can spare an extra cpu core
for that. Then you can run an extra thread that signals your perl
interpreter. This means you can get a very exact timing source while your
perl code is number crunching, without even using a syscall to communicate
between your threads.

For example the deliantra game server uses a variant of this technique
to interrupt background processes regularly to send map updates to game
clients.

Or L<EV::Loop::Async> uses an interrupt object to wake up perl when new
events have arrived.

L<IO::AIO> and L<BDB> could also use this to speed up result reporting.

=item Speedy event loop invocation

One could use this module e.g. in L<Coro> to interrupt a running coro-thread
and cause it to enter the event loop.

Or one could bind to C<SIGIO> and tell some important sockets to send this
signal, causing the event loop to be entered to reduce network latency.

=back

=head2 HOW TO USE

You can use this module by creating an C<Async::Interrupt> object for each
such event source. This object stores a perl and/or a C-level callback
that is invoked when the C<Async::Interrupt> object gets signalled. It is
executed at the next time the perl interpreter is running (i.e. it will
interrupt a computation, but not an XS function or a syscall).

You can signal the C<Async::Interrupt> object either by calling it's C<<
->signal >> method, or, more commonly, by calling a C function. There is
also the built-in (POSIX) signal source.

The C<< ->signal_func >> returns the address of the C function that is to
be called (plus an argument to be used during the call). The signalling
function also takes an integer argument in the range SIG_ATOMIC_MIN to
SIG_ATOMIC_MAX (guaranteed to allow at least 0..127).

Since this kind of interruption is fast, but can only interrupt a
I<running> interpreter, there is optional support for signalling a pipe
- that means you can also wait for the pipe to become readable (e.g. via
L<EV> or L<AnyEvent>). This, of course, incurs the overhead of a C<read>
and C<write> syscall.

=head1 USAGE EXAMPLES

=head2 Implementing race-free signal handling

This example uses a single event pipe for all signals, and one
Async::Interrupt per signal. This code is actually what the L<AnyEvent>
module uses itself when Async::Interrupt is available.

First, create the event pipe and hook it into the event loop

   $SIGPIPE = new Async::Interrupt::EventPipe;
   $SIGPIPE_W = AnyEvent->io (
      fh   => $SIGPIPE->fileno,
      poll => "r",
      cb   => \&_signal_check, # defined later
   );

Then, for each signal to hook, create an Async::Interrupt object. The
callback just sets a global variable, as we are only interested in
synchronous signals (i.e. when the event loop polls), which is why the
pipe draining is not done automatically.

   my $interrupt = new Async::Interrupt
      cb             => sub { undef $SIGNAL_RECEIVED{$signum} },
      signal         => $signum,
      pipe           => [$SIGPIPE->filenos],
      pipe_autodrain => 0,
   ;

Finally, the I/O callback for the event pipe handles the signals:



( run in 0.757 second using v1.01-cache-2.11-cpan-df04353d9ac )