Async-Interrupt

 view release on metacpan or  search on metacpan

Interrupt.pm  view on Meta::CPAN

=head1 NAME

Async::Interrupt - allow C/XS libraries to interrupt perl asynchronously

=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

Interrupt.pm  view on Meta::CPAN


   $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:

Interrupt.pm  view on Meta::CPAN

   # urgs, reminds me of Event
   for my $attr (qw(pipe_autodrain signal_hysteresis)) {
      $self->$attr ($arg{$attr}) if exists $arg{$attr};
   }

   $self
}

=item ($signal_func, $signal_arg) = $async->signal_func

Returns the address of a function to call asynchronously. The function
has the following prototype and needs to be passed the specified
C<$signal_arg>, which is a C<void *> cast to C<IV>:

   void (*signal_func) (void *signal_arg, int value)

An example call would look like:

   signal_func (signal_arg, 0);

The function is safe to call from within signal and thread contexts, at
any time. The specified C<value> is passed to both C and Perl callback.

C<$value> must be in the valid range for a C<sig_atomic_t>, except C<0>
(1..127 is portable).

If the function is called while the Async::Interrupt object is already
signaled but before the callbacks are being executed, then the stored
C<value> is either the old or the new one. Due to the asynchronous
nature of the code, the C<value> can even be passed to two consecutive
invocations of the callback.

=item $address = $async->c_var

Returns the address (cast to IV) of an C<IV> variable. The variable is set
to C<0> initially and gets set to the passed value whenever the object
gets signalled, and reset to C<0> once the interrupt has been handled.

Note that it is often beneficial to just call C<PERL_ASYNC_CHECK ()> to

Interrupt.pm  view on Meta::CPAN


=item $async->handle

Calls the callback if the object is pending.

This method does not need to be called normally, as it will be invoked
automatically. However, it can be used to force handling of outstanding
interrupts while the object is blocked.

One reason why one might want to do that is when you want to switch
from asynchronous interruptions to synchronous one, using e.g. an event
loop. To do that, one would first C<< $async->block >> the interrupt
object, then register a read watcher on the C<pipe_fileno> that calls C<<
$async->handle >>.

This disables asynchronous interruptions, but ensures that interrupts are
handled by the event loop.

=item $async->signal_hysteresis ($enable)

Enables or disables signal hysteresis (default: disabled). If a POSIX
signal is used as a signal source for the interrupt object, then enabling
signal hysteresis causes Async::Interrupt to reset the signal action to
C<SIG_IGN> in the signal handler and restore it just before handling the
interruption.

Interrupt.pm  view on Meta::CPAN

These two convenience functions simply convert a signal name or number to
the corresponding name or number. They are not used by this module and
exist just because perl doesn't have a nice way to do this on its own.

They will return C<undef> on illegal names or numbers.

=back

=head1 THE Async::Interrupt::EventPipe CLASS

Pipes are the predominant utility to make asynchronous signals
synchronous. However, pipes are hard to come by: they don't exist on the
broken windows platform, and on GNU/Linux systems, you might want to use
an C<eventfd> instead.

This class creates selectable event pipes in a portable fashion: on
windows, it will try to create a tcp socket pair, on GNU/Linux, it will
try to create an eventfd and everywhere else it will try to use a normal
pipe.

=over 4

README  view on Meta::CPAN

NAME
    Async::Interrupt - allow C/XS libraries to interrupt perl asynchronously

SYNOPSIS
     use Async::Interrupt;

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.

  USAGE SCENARIOS
    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 "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.

README  view on Meta::CPAN


       $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:

README  view on Meta::CPAN


            If you want to share a single event pipe between multiple
            Async::Interrupt objects, you can use the
            "Async::Interrupt::EventPipe" class to manage those.

        pipe_autodrain => $boolean
            Sets the initial autodrain state, see the "pipe_autodrain"
            method, below.

    ($signal_func, $signal_arg) = $async->signal_func
        Returns the address of a function to call asynchronously. The
        function has the following prototype and needs to be passed the
        specified $signal_arg, which is a "void *" cast to "IV":

           void (*signal_func) (void *signal_arg, int value)

        An example call would look like:

           signal_func (signal_arg, 0);

        The function is safe to call from within signal and thread contexts,
        at any time. The specified "value" is passed to both C and Perl
        callback.

        $value must be in the valid range for a "sig_atomic_t", except 0
        (1..127 is portable).

        If the function is called while the Async::Interrupt object is
        already signaled but before the callbacks are being executed, then
        the stored "value" is either the old or the new one. Due to the
        asynchronous nature of the code, the "value" can even be passed to
        two consecutive invocations of the callback.

    $address = $async->c_var
        Returns the address (cast to IV) of an "IV" variable. The variable
        is set to 0 initially and gets set to the passed value whenever the
        object gets signalled, and reset to 0 once the interrupt has been
        handled.

        Note that it is often beneficial to just call "PERL_ASYNC_CHECK ()"
        to handle any interrupts.

README  view on Meta::CPAN

        (1..127 is portable).

    $async->handle
        Calls the callback if the object is pending.

        This method does not need to be called normally, as it will be
        invoked automatically. However, it can be used to force handling of
        outstanding interrupts while the object is blocked.

        One reason why one might want to do that is when you want to switch
        from asynchronous interruptions to synchronous one, using e.g. an
        event loop. To do that, one would first "$async->block" the
        interrupt object, then register a read watcher on the "pipe_fileno"
        that calls "$async->handle".

        This disables asynchronous interruptions, but ensures that
        interrupts are handled by the event loop.

    $async->signal_hysteresis ($enable)
        Enables or disables signal hysteresis (default: disabled). If a
        POSIX signal is used as a signal source for the interrupt object,
        then enabling signal hysteresis causes Async::Interrupt to reset the
        signal action to "SIG_IGN" in the signal handler and restore it just
        before handling the interruption.

        When you expect a lot of signals (e.g. when using SIGIO), then

README  view on Meta::CPAN

    $signum = Async::Interrupt::sig2num $signame_or_number
    $signame = Async::Interrupt::sig2name $signame_or_number
        These two convenience functions simply convert a signal name or
        number to the corresponding name or number. They are not used by
        this module and exist just because perl doesn't have a nice way to
        do this on its own.

        They will return "undef" on illegal names or numbers.

THE Async::Interrupt::EventPipe CLASS
    Pipes are the predominant utility to make asynchronous signals
    synchronous. However, pipes are hard to come by: they don't exist on the
    broken windows platform, and on GNU/Linux systems, you might want to use
    an "eventfd" instead.

    This class creates selectable event pipes in a portable fashion: on
    windows, it will try to create a tcp socket pair, on GNU/Linux, it will
    try to create an eventfd and everywhere else it will try to use a normal
    pipe.

    $epipe = new Async::Interrupt::EventPipe
        This creates and returns an eventpipe object. This object is simply

ecb.h  view on Meta::CPAN

    #define ECB_MEMORY_FENCE_RELAXED __atomic_thread_fence (__ATOMIC_RELAXED)

  #elif ECB_CLANG_EXTENSION(c_atomic)
    /* see comment below (stdatomic.h) about the C11 memory model. */
    #define ECB_MEMORY_FENCE         __c11_atomic_thread_fence (__ATOMIC_SEQ_CST)
    #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE)
    #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE)
    #define ECB_MEMORY_FENCE_RELAXED __c11_atomic_thread_fence (__ATOMIC_RELAXED)

  #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__
    #define ECB_MEMORY_FENCE         __sync_synchronize ()
  #elif _MSC_VER >= 1500 /* VC++ 2008 */
    /* apparently, microsoft broke all the memory barrier stuff in Visual Studio 2008... */
    #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
    #define ECB_MEMORY_FENCE         _ReadWriteBarrier (); MemoryBarrier()
    #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier (); MemoryBarrier() /* according to msdn, _ReadBarrier is not a load fence */
    #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier (); MemoryBarrier()
  #elif _MSC_VER >= 1400 /* VC++ 2005 */
    #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
    #define ECB_MEMORY_FENCE         _ReadWriteBarrier ()
    #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */



( run in 0.378 second using v1.01-cache-2.11-cpan-0d8aa00de5b )