Async-Interrupt
view release on metacpan or search on metacpan
Finally, the I/O callback for the event pipe handles the signals:
sub _signal_check {
# drain the pipe first
$SIGPIPE->drain;
# two loops, just to be sure
while (%SIGNAL_RECEIVED) {
for (keys %SIGNAL_RECEIVED) {
delete $SIGNAL_RECEIVED{$_};
warn "signal $_ received\n";
}
}
}
Interrupt perl from another thread
This example interrupts the Perl interpreter from another thread, via
the XS API. This is used by e.g. the EV::Loop::Async module.
On the Perl level, a new loop object (which contains the thread) is
created, by first calling some XS constructor, querying the C-level
callback function and feeding that as the "c_cb" into the
Async::Interrupt constructor:
my $self = XS_thread_constructor;
my ($c_func, $c_arg) = _c_func $self; # return the c callback
my $asy = new Async::Interrupt c_cb => [$c_func, $c_arg];
Then the newly created Interrupt object is queried for the signaling
function that the newly created thread should call, and this is in turn
told to the thread object:
_attach $self, $asy->signal_func;
So to repeat: first the XS object is created, then it is queried for the
callback that should be called when the Interrupt object gets signalled.
Then the interrupt object is queried for the callback function that the
thread should call to signal the Interrupt object, and this callback is
then attached to the thread.
You have to be careful that your new thread is not signalling before the
signal function was configured, for example by starting the background
thread only within "_attach".
That concludes the Perl part.
The XS part consists of the actual constructor which creates a thread,
which is not relevant for this example, and two functions, "_c_func",
which returns the Perl-side callback, and "_attach", which configures
the signalling functioon that is safe toc all from another thread. For
simplicity, we will use global variables to store the functions,
normally you would somehow attach them to $self.
The "c_func" simply returns the address of a static function and
arranges for the object pointed to by $self to be passed to it, as an
integer:
void
_c_func (SV *loop)
PPCODE:
EXTEND (SP, 2);
PUSHs (sv_2mortal (newSViv (PTR2IV (c_func))));
PUSHs (sv_2mortal (newSViv (SvRV (loop))));
This would be the callback (since it runs in a normal Perl context, it
is permissible to manipulate Perl values):
static void
c_func (pTHX_ void *loop_, int value)
{
SV *loop_object = (SV *)loop_;
...
}
And this attaches the signalling callback:
static void (*my_sig_func) (void *signal_arg, int value);
static void *my_sig_arg;
void
_attach (SV *loop_, IV sig_func, void *sig_arg)
CODE:
{
my_sig_func = sig_func;
my_sig_arg = sig_arg;
/* now run the thread */
thread_create (&u->tid, l_run, 0);
}
And "l_run" (the background thread) would eventually call the signaling
function:
my_sig_func (my_sig_arg, 0);
You can have a look at EV::Loop::Async for an actual example using
intra-thread communication, locking and so on.
THE Async::Interrupt CLASS
$async = new Async::Interrupt key => value...
Creates a new Async::Interrupt object. You may only use async
notifications on this object while it exists, so you need to keep a
reference to it at all times while it is used.
Optional constructor arguments include (normally you would specify
at least one of "cb" or "c_cb").
cb => $coderef->($value)
Registers a perl callback to be invoked whenever the async
interrupt is signalled.
Note that, since this callback can be invoked at basically any
time, it must not modify any well-known global variables such as
$/ without restoring them again before returning.
The exceptions are $! and $@, which are saved and restored by
Async::Interrupt.
If the callback should throw an exception, then it will be
caught, and $Async::Interrupt::DIED will be called with $@
( run in 0.470 second using v1.01-cache-2.11-cpan-71847e10f99 )