… | |
… | |
29 | typedef struct { |
29 | typedef struct { |
30 | SV *cb; |
30 | SV *cb; |
31 | void (*c_cb)(pTHX_ void *c_arg, int value); |
31 | void (*c_cb)(pTHX_ void *c_arg, int value); |
32 | void *c_arg; |
32 | void *c_arg; |
33 | SV *fh_r, *fh_w; |
33 | SV *fh_r, *fh_w; |
|
|
34 | SV *value; |
34 | int signum; |
35 | int signum; |
35 | volatile int blocked; |
36 | volatile int blocked; |
36 | |
37 | |
37 | int fd_r; |
38 | s_epipe ep; |
38 | volatile int fd_w; |
|
|
39 | int fd_wlen; |
39 | int fd_wlen; |
40 | atomic_t fd_enable; |
40 | atomic_t fd_enable; |
41 | atomic_t value; |
|
|
42 | atomic_t pending; |
41 | atomic_t pending; |
|
|
42 | volatile IV *valuep; |
43 | } async_t; |
43 | } async_t; |
44 | |
44 | |
45 | static AV *asyncs; |
45 | static AV *asyncs; |
46 | static async_t *sig_async [SIG_SIZE]; |
46 | static async_t *sig_async [SIG_SIZE]; |
47 | |
47 | |
… | |
… | |
55 | static char pipedata [8]; |
55 | static char pipedata [8]; |
56 | |
56 | |
57 | async_t *async = (async_t *)signal_arg; |
57 | async_t *async = (async_t *)signal_arg; |
58 | int pending = async->pending; |
58 | int pending = async->pending; |
59 | |
59 | |
60 | async->value = value; |
60 | *async->valuep = value ? value : 1; |
61 | async->pending = 1; |
61 | async->pending = 1; |
62 | async_pending = 1; |
62 | async_pending = 1; |
63 | psig_pend [9] = 1; |
63 | psig_pend [9] = 1; |
64 | *sig_pending = 1; |
64 | *sig_pending = 1; |
65 | |
65 | |
66 | { |
66 | { |
67 | int fd_w = async->fd_w; |
|
|
68 | int fd_enable = async->fd_enable; |
67 | int fd_enable = async->fd_enable; |
69 | |
68 | |
70 | if (!pending && fd_w >= 0 && fd_enable) |
69 | if (!pending && fd_enable && async->ep.fd [1] >= 0) |
71 | if (write (fd_w, pipedata, async->fd_wlen) < 0 && errno == EINVAL) |
70 | s_epipe_signal (&async->ep); |
72 | /* on EINVAL we assume it's an eventfd */ |
|
|
73 | write (fd_w, pipedata, (async->fd_wlen = 8)); |
|
|
74 | } |
71 | } |
75 | } |
72 | } |
76 | |
73 | |
77 | static void |
74 | static void |
78 | handle_async (async_t *async) |
75 | handle_async (async_t *async) |
79 | { |
76 | { |
80 | int old_errno = errno; |
77 | int old_errno = errno; |
81 | int value = async->value; |
78 | int value = *async->valuep; |
82 | |
79 | |
|
|
80 | *async->valuep = 0; |
83 | async->pending = 0; |
81 | async->pending = 0; |
84 | |
82 | |
85 | /* drain pipe */ |
83 | /* drain pipe */ |
86 | if (async->fd_r >= 0 && async->fd_enable) |
84 | if (async->fd_enable && async->ep.fd [0] >= 0) |
87 | { |
85 | s_epipe_drain (&async->ep); |
88 | char dummy [9]; /* 9 is enough for eventfd and normal pipes */ |
|
|
89 | |
|
|
90 | while (read (async->fd_r, dummy, sizeof (dummy)) == sizeof (dummy)) |
|
|
91 | ; |
|
|
92 | } |
|
|
93 | |
86 | |
94 | if (async->c_cb) |
87 | if (async->c_cb) |
95 | { |
88 | { |
96 | dTHX; |
89 | dTHX; |
97 | async->c_cb (aTHX_ async->c_arg, value); |
90 | async->c_cb (aTHX_ async->c_arg, value); |
… | |
… | |
208 | CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */ |
201 | CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */ |
209 | |
202 | |
210 | PROTOTYPES: DISABLE |
203 | PROTOTYPES: DISABLE |
211 | |
204 | |
212 | void |
205 | void |
213 | _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl) |
206 | _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue) |
214 | PPCODE: |
207 | PPCODE: |
215 | { |
208 | { |
216 | SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0; |
209 | SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0; |
217 | int fd_r = SvOK (fh_r) ? s_fileno_croak (fh_r, 0) : -1; |
|
|
218 | int fd_w = SvOK (fh_w) ? s_fileno_croak (fh_w, 1) : -1; |
|
|
219 | async_t *async; |
210 | async_t *async; |
220 | |
211 | |
221 | Newz (0, async, 1, async_t); |
212 | Newz (0, async, 1, async_t); |
222 | |
213 | |
223 | XPUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
214 | XPUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
|
|
215 | /* TODO: need to bless right now to ensure deallocation */ |
224 | av_push (asyncs, TOPs); |
216 | av_push (asyncs, TOPs); |
225 | |
217 | |
226 | async->fh_r = fd_r >= 0 ? newSVsv (fh_r) : 0; async->fd_r = fd_r; |
218 | SvGETMAGIC (fh_r); SvGETMAGIC (fh_w); |
227 | async->fh_w = fd_w >= 0 ? newSVsv (fh_w) : 0; async->fd_w = fd_w; |
219 | if (SvOK (fh_r) || SvOK (fh_w)) |
|
|
220 | { |
|
|
221 | int fd_r = s_fileno_croak (fh_r, 0); |
|
|
222 | int fd_w = s_fileno_croak (fh_w, 1); |
|
|
223 | |
|
|
224 | async->fh_r = newSVsv (fh_r); |
|
|
225 | async->fh_w = newSVsv (fh_w); |
|
|
226 | async->ep.fd [0] = fd_r; |
|
|
227 | async->ep.fd [1] = fd_w; |
228 | async->fd_wlen = 1; |
228 | async->ep.len = 1; |
229 | async->fd_enable = 1; |
229 | async->fd_enable = 1; |
|
|
230 | } |
|
|
231 | |
|
|
232 | async->value = SvROK (pvalue) |
|
|
233 | ? SvREFCNT_inc_NN (SvRV (pvalue)) |
|
|
234 | : NEWSV (0, 0); |
|
|
235 | |
|
|
236 | sv_setiv (async->value, 0); |
|
|
237 | SvIOK_only (async->value); /* just to be sure */ |
|
|
238 | SvREADONLY_on (async->value); |
|
|
239 | |
|
|
240 | async->valuep = &(SvIVX (async->value)); |
|
|
241 | |
230 | async->cb = cv; |
242 | async->cb = cv; |
231 | async->c_cb = c_cb; |
243 | async->c_cb = c_cb; |
232 | async->c_arg = c_arg; |
244 | async->c_arg = c_arg; |
233 | async->signum = SvOK (signl) ? s_signum_croak (signl) : 0; |
245 | async->signum = SvOK (signl) ? s_signum_croak (signl) : 0; |
234 | |
246 | |
… | |
… | |
256 | PPCODE: |
268 | PPCODE: |
257 | EXTEND (SP, 2); |
269 | EXTEND (SP, 2); |
258 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
270 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
259 | PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
271 | PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
260 | |
272 | |
|
|
273 | IV |
|
|
274 | c_var (async_t *async) |
|
|
275 | CODE: |
|
|
276 | RETVAL = PTR2IV (async->valuep); |
|
|
277 | OUTPUT: |
|
|
278 | RETVAL |
|
|
279 | |
261 | void |
280 | void |
262 | signal (async_t *async, int value = 0) |
281 | signal (async_t *async, int value = 1) |
263 | CODE: |
282 | CODE: |
264 | async_signal (async, value); |
283 | async_signal (async, value); |
265 | |
284 | |
266 | void |
285 | void |
267 | block (async_t *async) |
286 | block (async_t *async) |
… | |
… | |
291 | ALIAS: |
310 | ALIAS: |
292 | pipe_enable = 1 |
311 | pipe_enable = 1 |
293 | pipe_disable = 0 |
312 | pipe_disable = 0 |
294 | CODE: |
313 | CODE: |
295 | async->fd_enable = ix; |
314 | async->fd_enable = ix; |
|
|
315 | |
|
|
316 | int |
|
|
317 | pipe_fileno (async_t *async) |
|
|
318 | CODE: |
|
|
319 | if (!async->ep.len) |
|
|
320 | { |
|
|
321 | int res; |
|
|
322 | |
|
|
323 | /*block (async);*//*TODO*/ |
|
|
324 | res = s_epipe_new (&async->ep); |
|
|
325 | async->fd_enable = 1; |
|
|
326 | /*unblock (async);*//*TODO*/ |
|
|
327 | |
|
|
328 | if (res < 0) |
|
|
329 | croak ("Async::Interrupt: unable to initialize event pipe"); |
|
|
330 | } |
|
|
331 | |
|
|
332 | RETVAL = async->ep.fd [0]; |
|
|
333 | OUTPUT: |
|
|
334 | RETVAL |
|
|
335 | |
|
|
336 | |
|
|
337 | void |
|
|
338 | post_fork (async_t *async) |
|
|
339 | CODE: |
|
|
340 | if (async->ep.len) |
|
|
341 | { |
|
|
342 | int res; |
|
|
343 | |
|
|
344 | /*block (async);*//*TODO*/ |
|
|
345 | res = s_epipe_renew (&async->ep); |
|
|
346 | /*unblock (async);*//*TODO*/ |
|
|
347 | |
|
|
348 | if (res < 0) |
|
|
349 | croak ("Async::Interrupt: unable to initialize event pipe after fork"); |
|
|
350 | } |
296 | |
351 | |
297 | void |
352 | void |
298 | DESTROY (SV *self) |
353 | DESTROY (SV *self) |
299 | CODE: |
354 | CODE: |
300 | { |
355 | { |
… | |
… | |
328 | sigaction (async->signum, &sa, 0); |
383 | sigaction (async->signum, &sa, 0); |
329 | } |
384 | } |
330 | #endif |
385 | #endif |
331 | } |
386 | } |
332 | |
387 | |
|
|
388 | if (!async->fh_r && async->ep.len) |
|
|
389 | s_epipe_destroy (&async->ep); |
|
|
390 | |
333 | SvREFCNT_dec (async->fh_r); |
391 | SvREFCNT_dec (async->fh_r); |
334 | SvREFCNT_dec (async->fh_w); |
392 | SvREFCNT_dec (async->fh_w); |
335 | SvREFCNT_dec (async->cb); |
393 | SvREFCNT_dec (async->cb); |
|
|
394 | SvREFCNT_dec (async->value); |
336 | |
395 | |
337 | Safefree (async); |
396 | Safefree (async); |
338 | } |
397 | } |
339 | |
398 | |