--- cvsroot/Async-Interrupt/Interrupt.pm 2009/07/28 13:17:05 1.19 +++ cvsroot/Async-Interrupt/Interrupt.pm 2009/07/28 13:35:57 1.20 @@ -142,7 +142,85 @@ This example interrupts the Perl interpreter from another thread, via the XS API. This is used by e.g. the L module. -#TODO# +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 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 fucntion 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 C<_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<_c_func>, +which returns the Perl-side callback, and C<_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 C<$self>. + +The C simply returns the address of a static function and arranges +for the object pointed to by C<$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 C (the background thread) would eventually call the signaling +function: + + my_sig_func (my_sig_arg, 0); + +You can have a look at L for an actual example using +intra-thread communication, locking and so on. + =head1 THE Async::Interrupt CLASS