… | |
… | |
140 | =head2 Interrupt perl from another thread |
140 | =head2 Interrupt perl from another thread |
141 | |
141 | |
142 | This example interrupts the Perl interpreter from another thread, via the |
142 | This example interrupts the Perl interpreter from another thread, via the |
143 | XS API. This is used by e.g. the L<EV::Loop::Async> module. |
143 | XS API. This is used by e.g. the L<EV::Loop::Async> module. |
144 | |
144 | |
145 | #TODO# |
145 | On the Perl level, a new loop object (which contains the thread) |
|
|
146 | is created, by first calling some XS constructor, querying the |
|
|
147 | C-level callback function and feeding that as the C<c_cb> into the |
|
|
148 | Async::Interrupt constructor: |
|
|
149 | |
|
|
150 | my $self = XS_thread_constructor; |
|
|
151 | my ($c_func, $c_arg) = _c_func $self; # return the c callback |
|
|
152 | my $asy = new Async::Interrupt c_cb => [$c_func, $c_arg]; |
|
|
153 | |
|
|
154 | Then the newly created Interrupt object is queried for the signaling |
|
|
155 | function that the newly created thread should call, and this is in turn |
|
|
156 | told to the thread object: |
|
|
157 | |
|
|
158 | _attach $self, $asy->signal_func; |
|
|
159 | |
|
|
160 | So to repeat: first the XS object is created, then it is queried for the |
|
|
161 | callback that should be called when the Interrupt object gets signalled. |
|
|
162 | |
|
|
163 | Then the interrupt object is queried for the callback fucntion that the |
|
|
164 | thread should call to signal the Interrupt object, and this callback is |
|
|
165 | then attached to the thread. |
|
|
166 | |
|
|
167 | You have to be careful that your new thread is not signalling before the |
|
|
168 | signal function was configured, for example by starting the background |
|
|
169 | thread only within C<_attach>. |
|
|
170 | |
|
|
171 | That concludes the Perl part. |
|
|
172 | |
|
|
173 | The XS part consists of the actual constructor which creates a thread, |
|
|
174 | which is not relevant for this example, and two functions, C<_c_func>, |
|
|
175 | which returns the Perl-side callback, and C<_attach>, which configures |
|
|
176 | the signalling functioon that is safe toc all from another thread. For |
|
|
177 | simplicity, we will use global variables to store the functions, normally |
|
|
178 | you would somehow attach them to C<$self>. |
|
|
179 | |
|
|
180 | The C<c_func> simply returns the address of a static function and arranges |
|
|
181 | for the object pointed to by C<$self> to be passed to it, as an integer: |
|
|
182 | |
|
|
183 | void |
|
|
184 | _c_func (SV *loop) |
|
|
185 | PPCODE: |
|
|
186 | EXTEND (SP, 2); |
|
|
187 | PUSHs (sv_2mortal (newSViv (PTR2IV (c_func)))); |
|
|
188 | PUSHs (sv_2mortal (newSViv (SvRV (loop)))); |
|
|
189 | |
|
|
190 | This would be the callback (since it runs in a normal Perl context, it is |
|
|
191 | permissible to manipulate Perl values): |
|
|
192 | |
|
|
193 | static void |
|
|
194 | c_func (pTHX_ void *loop_, int value) |
|
|
195 | { |
|
|
196 | SV *loop_object = (SV *)loop_; |
|
|
197 | ... |
|
|
198 | } |
|
|
199 | |
|
|
200 | And this attaches the signalling callback: |
|
|
201 | |
|
|
202 | static void (*my_sig_func) (void *signal_arg, int value); |
|
|
203 | static void *my_sig_arg; |
|
|
204 | |
|
|
205 | void |
|
|
206 | _attach (SV *loop_, IV sig_func, void *sig_arg) |
|
|
207 | CODE: |
|
|
208 | { |
|
|
209 | my_sig_func = sig_func; |
|
|
210 | my_sig_arg = sig_arg; |
|
|
211 | |
|
|
212 | /* now run the thread */ |
|
|
213 | thread_create (&u->tid, l_run, 0); |
|
|
214 | } |
|
|
215 | |
|
|
216 | And C<l_run> (the background thread) would eventually call the signaling |
|
|
217 | function: |
|
|
218 | |
|
|
219 | my_sig_func (my_sig_arg, 0); |
|
|
220 | |
|
|
221 | You can have a look at L<EV::Loop::Async> for an actual example using |
|
|
222 | intra-thread communication, locking and so on. |
|
|
223 | |
146 | |
224 | |
147 | =head1 THE Async::Interrupt CLASS |
225 | =head1 THE Async::Interrupt CLASS |
148 | |
226 | |
149 | =over 4 |
227 | =over 4 |
150 | |
228 | |