… | |
… | |
32 | void *c_arg; |
32 | void *c_arg; |
33 | SV *fh_r, *fh_w; |
33 | SV *fh_r, *fh_w; |
34 | SV *value; |
34 | SV *value; |
35 | int signum; |
35 | int signum; |
36 | int autodrain; |
36 | int autodrain; |
|
|
37 | ANY *scope_savestack; |
37 | volatile int blocked; |
38 | volatile int blocked; |
38 | |
39 | |
39 | s_epipe ep; |
40 | s_epipe ep; |
40 | int fd_wlen; |
41 | int fd_wlen; |
41 | atomic_t fd_enable; |
42 | atomic_t fd_enable; |
42 | atomic_t pending; |
43 | atomic_t pending; |
43 | volatile IV *valuep; |
44 | volatile IV *valuep; |
|
|
45 | atomic_t hysteresis; |
44 | } async_t; |
46 | } async_t; |
45 | |
47 | |
46 | static AV *asyncs; |
48 | static AV *asyncs; |
47 | static async_t *sig_async [SIG_SIZE]; |
49 | static async_t *sig_async [SIG_SIZE]; |
48 | |
50 | |
49 | #define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv)) |
51 | #define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv)) |
50 | #define SvASYNC(rv) SvASYNC_nrv (SvRV (rv)) |
52 | #define SvASYNC(rv) SvASYNC_nrv (SvRV (rv)) |
51 | |
53 | |
|
|
54 | static void async_signal (void *signal_arg, int value); |
|
|
55 | |
|
|
56 | static void |
|
|
57 | setsig (int signum, void (*handler)(int)) |
|
|
58 | { |
|
|
59 | #if _WIN32 |
|
|
60 | signal (async->signum, handler); |
|
|
61 | #else |
|
|
62 | struct sigaction sa; |
|
|
63 | sa.sa_handler = handler; |
|
|
64 | sigfillset (&sa.sa_mask); |
|
|
65 | sa.sa_flags = 0; /* if we interrupt a syscall, we might drain the pipe before it became ready */ |
|
|
66 | sigaction (signum, &sa, 0); |
|
|
67 | } |
|
|
68 | |
|
|
69 | static void |
|
|
70 | async_sigsend (int signum) |
|
|
71 | { |
|
|
72 | async_signal (sig_async [signum], 0); |
|
|
73 | } |
|
|
74 | |
52 | /* the main workhorse to signal */ |
75 | /* the main workhorse to signal */ |
53 | static void |
76 | static void |
54 | async_signal (void *signal_arg, int value) |
77 | async_signal (void *signal_arg, int value) |
55 | { |
78 | { |
56 | static char pipedata [8]; |
79 | static char pipedata [8]; |
57 | |
80 | |
58 | async_t *async = (async_t *)signal_arg; |
81 | async_t *async = (async_t *)signal_arg; |
59 | int pending = async->pending; |
82 | int pending = async->pending; |
|
|
83 | |
|
|
84 | if (async->hysteresis) |
|
|
85 | setsig (async->signum, SIG_IGN); |
60 | |
86 | |
61 | *async->valuep = value ? value : 1; |
87 | *async->valuep = value ? value : 1; |
62 | async->pending = 1; |
88 | async->pending = 1; |
63 | async_pending = 1; |
89 | async_pending = 1; |
64 | psig_pend [9] = 1; |
90 | psig_pend [9] = 1; |
… | |
… | |
75 | int value = *async->valuep; |
101 | int value = *async->valuep; |
76 | |
102 | |
77 | *async->valuep = 0; |
103 | *async->valuep = 0; |
78 | async->pending = 0; |
104 | async->pending = 0; |
79 | |
105 | |
|
|
106 | /* restore signal */ |
|
|
107 | if (async->hysteresis) |
|
|
108 | setsig (async->signum, async_sigsend); |
|
|
109 | |
80 | /* drain pipe */ |
110 | /* drain pipe */ |
81 | if (async->fd_enable && async->ep.len && async->autodrain) |
111 | if (async->fd_enable && async->ep.len && async->autodrain) |
82 | s_epipe_drain (&async->ep); |
112 | s_epipe_drain (&async->ep); |
83 | |
113 | |
84 | if (async->c_cb) |
114 | if (async->c_cb) |
… | |
… | |
136 | |
166 | |
137 | async_pending = 0; |
167 | async_pending = 0; |
138 | |
168 | |
139 | for (i = AvFILLp (asyncs); i >= 0; --i) |
169 | for (i = AvFILLp (asyncs); i >= 0; --i) |
140 | { |
170 | { |
|
|
171 | SV *async_sv = AvARRAY (asyncs)[i]; |
141 | async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]); |
172 | async_t *async = SvASYNC_nrv (async_sv); |
142 | |
173 | |
143 | if (async->pending && !async->blocked) |
174 | if (async->pending && !async->blocked) |
|
|
175 | { |
|
|
176 | /* temporarily keep a refcount */ |
|
|
177 | SvREFCNT_inc (async_sv); |
144 | handle_async (async); |
178 | handle_async (async); |
|
|
179 | SvREFCNT_dec (async_sv); |
|
|
180 | |
|
|
181 | /* the handler could have deleted any number of asyncs */ |
|
|
182 | if (i > AvFILLp (asyncs)) |
|
|
183 | i = AvFILLp (asyncs); |
|
|
184 | } |
145 | } |
185 | } |
146 | } |
186 | } |
147 | |
187 | |
148 | #if HAS_SA_SIGINFO |
188 | #if HAS_SA_SIGINFO |
149 | static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg) |
189 | static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg) |
… | |
… | |
161 | else |
201 | else |
162 | old_sighandler (signum); |
202 | old_sighandler (signum); |
163 | } |
203 | } |
164 | #endif |
204 | #endif |
165 | |
205 | |
166 | static void |
|
|
167 | async_sigsend (int signum) |
|
|
168 | { |
|
|
169 | async_signal (sig_async [signum], 0); |
|
|
170 | } |
|
|
171 | |
|
|
172 | #define block(async) ++(async)->blocked |
206 | #define block(async) ++(async)->blocked |
173 | |
207 | |
174 | static void |
208 | static void |
175 | unblock (async_t *async) |
209 | unblock (async_t *async) |
176 | { |
210 | { |
… | |
… | |
181 | |
215 | |
182 | static void |
216 | static void |
183 | scope_block_cb (pTHX_ void *async_sv) |
217 | scope_block_cb (pTHX_ void *async_sv) |
184 | { |
218 | { |
185 | async_t *async = SvASYNC_nrv ((SV *)async_sv); |
219 | async_t *async = SvASYNC_nrv ((SV *)async_sv); |
|
|
220 | |
|
|
221 | async->scope_savestack = 0; |
186 | unblock (async); |
222 | unblock (async); |
187 | SvREFCNT_dec (async_sv); |
223 | SvREFCNT_dec (async_sv); |
188 | } |
224 | } |
189 | |
225 | |
|
|
226 | static void |
|
|
227 | scope_block (SV *async_sv) |
|
|
228 | { |
|
|
229 | async_t *async = SvASYNC_nrv (async_sv); |
|
|
230 | |
|
|
231 | /* as a heuristic, we skip the scope block if we already are blocked */ |
|
|
232 | /* and the existing scope block used the same savestack */ |
|
|
233 | |
|
|
234 | if (!async->scope_savestack || async->scope_savestack != PL_savestack) |
|
|
235 | { |
|
|
236 | async->scope_savestack = PL_savestack; |
|
|
237 | block (async); |
|
|
238 | |
|
|
239 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
|
|
240 | SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv)); |
|
|
241 | ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
|
|
242 | } |
|
|
243 | } |
|
|
244 | |
|
|
245 | #endif |
190 | MODULE = Async::Interrupt PACKAGE = Async::Interrupt |
246 | MODULE = Async::Interrupt PACKAGE = Async::Interrupt |
191 | |
247 | |
192 | BOOT: |
248 | BOOT: |
193 | old_sighandler = PL_sighandlerp; |
249 | old_sighandler = PL_sighandlerp; |
194 | PL_sighandlerp = async_sighandler; |
250 | PL_sighandlerp = async_sighandler; |
… | |
… | |
246 | { |
302 | { |
247 | if (async->signum < 0) |
303 | if (async->signum < 0) |
248 | croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl)); |
304 | croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl)); |
249 | |
305 | |
250 | sig_async [async->signum] = async; |
306 | sig_async [async->signum] = async; |
251 | #if _WIN32 |
|
|
252 | signal (async->signum, async_sigsend); |
307 | setsig (async->signum, async_sigsend); |
253 | #else |
|
|
254 | { |
|
|
255 | struct sigaction sa = { }; |
|
|
256 | sa.sa_handler = async_sigsend; |
|
|
257 | sigfillset (&sa.sa_mask); |
|
|
258 | sigaction (async->signum, &sa, 0); |
|
|
259 | } |
|
|
260 | #endif |
|
|
261 | } |
308 | } |
262 | } |
309 | } |
|
|
310 | |
|
|
311 | void |
|
|
312 | signal_hysteresis (async_t *async, int enable) |
|
|
313 | CODE: |
|
|
314 | async->hysteresis = enable; |
263 | |
315 | |
264 | void |
316 | void |
265 | signal_func (async_t *async) |
317 | signal_func (async_t *async) |
266 | PPCODE: |
318 | PPCODE: |
267 | EXTEND (SP, 2); |
319 | EXTEND (SP, 2); |
268 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
320 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
269 | PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
321 | PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
270 | |
322 | |
|
|
323 | void |
|
|
324 | scope_block_func (SV *self) |
|
|
325 | PPCODE: |
|
|
326 | EXTEND (SP, 2); |
|
|
327 | PUSHs (sv_2mortal (newSViv (PTR2IV (scope_block)))); |
|
|
328 | PUSHs (sv_2mortal (newSViv (PTR2IV (SvRV (self))))); |
|
|
329 | |
271 | IV |
330 | IV |
272 | c_var (async_t *async) |
331 | c_var (async_t *async) |
273 | CODE: |
332 | CODE: |
274 | RETVAL = PTR2IV (async->valuep); |
333 | RETVAL = PTR2IV (async->valuep); |
275 | OUTPUT: |
334 | OUTPUT: |
… | |
… | |
291 | unblock (async); |
350 | unblock (async); |
292 | |
351 | |
293 | void |
352 | void |
294 | scope_block (SV *self) |
353 | scope_block (SV *self) |
295 | CODE: |
354 | CODE: |
296 | { |
355 | scope_block (SvRV (self)); |
297 | SV *async_sv = SvRV (self); |
|
|
298 | async_t *async = SvASYNC_nrv (async_sv); |
|
|
299 | block (async); |
|
|
300 | |
|
|
301 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
|
|
302 | SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv)); |
|
|
303 | ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
|
|
304 | } |
|
|
305 | |
356 | |
306 | void |
357 | void |
307 | pipe_enable (async_t *async) |
358 | pipe_enable (async_t *async) |
308 | ALIAS: |
359 | ALIAS: |
309 | pipe_enable = 1 |
360 | pipe_enable = 1 |
… | |
… | |
364 | async_t *async = SvASYNC_nrv (async_sv); |
415 | async_t *async = SvASYNC_nrv (async_sv); |
365 | |
416 | |
366 | for (i = AvFILLp (asyncs); i >= 0; --i) |
417 | for (i = AvFILLp (asyncs); i >= 0; --i) |
367 | if (AvARRAY (asyncs)[i] == async_sv) |
418 | if (AvARRAY (asyncs)[i] == async_sv) |
368 | { |
419 | { |
369 | if (i < AvFILLp (asyncs)) |
|
|
370 | AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)]; |
420 | AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)]; |
371 | |
421 | av_pop (asyncs); |
372 | assert (av_pop (asyncs) == async_sv); |
|
|
373 | goto found; |
422 | goto found; |
374 | } |
423 | } |
375 | |
424 | |
376 | if (!PL_dirty) |
425 | if (!PL_dirty) |
377 | warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report"); |
426 | warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report"); |
378 | |
427 | |
379 | found: |
428 | found: |
380 | |
429 | |
381 | if (async->signum) |
430 | if (async->signum) |
382 | { |
|
|
383 | #if _WIN32 |
|
|
384 | signal (async->signum, SIG_DFL); |
431 | setsig (async->signum, SIG_DFL); |
385 | #else |
|
|
386 | { |
|
|
387 | struct sigaction sa = { }; |
|
|
388 | sa.sa_handler = SIG_DFL; |
|
|
389 | sigaction (async->signum, &sa, 0); |
|
|
390 | } |
|
|
391 | #endif |
|
|
392 | } |
|
|
393 | |
432 | |
394 | if (!async->fh_r && async->ep.len) |
433 | if (!async->fh_r && async->ep.len) |
395 | s_epipe_destroy (&async->ep); |
434 | s_epipe_destroy (&async->ep); |
396 | |
435 | |
397 | SvREFCNT_dec (async->fh_r); |
436 | SvREFCNT_dec (async->fh_r); |