ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Async-Interrupt/Interrupt.xs
(Generate patch)

Comparing Async-Interrupt/Interrupt.xs (file contents):
Revision 1.10 by root, Fri Jul 17 03:32:29 2009 UTC vs.
Revision 1.19 by root, Tue Apr 24 22:01:59 2012 UTC

1#include "EXTERN.h" 1#include "EXTERN.h"
2#include "perl.h" 2#include "perl.h"
3#include "XSUB.h" 3#include "XSUB.h"
4 4
5#include "ecb.h"
5#include "schmorp.h" 6#include "schmorp.h"
6 7
7typedef volatile sig_atomic_t atomic_t; 8typedef volatile sig_atomic_t atomic_t;
8 9
9static int *sig_pending, *psig_pend; /* make local copies because of missing THX */ 10static int *sig_pending, *psig_pend; /* make local copies because of missing THX */
31 void (*c_cb)(pTHX_ void *c_arg, int value); 32 void (*c_cb)(pTHX_ void *c_arg, int value);
32 void *c_arg; 33 void *c_arg;
33 SV *fh_r, *fh_w; 34 SV *fh_r, *fh_w;
34 SV *value; 35 SV *value;
35 int signum; 36 int signum;
37 int autodrain;
38 ANY *scope_savestack;
36 volatile int blocked; 39 volatile int blocked;
37 40
38 s_epipe ep; 41 s_epipe ep;
39 int fd_wlen; 42 int fd_wlen;
40 atomic_t fd_enable; 43 atomic_t fd_enable;
41 atomic_t pending; 44 atomic_t pending;
42 volatile IV *valuep; 45 volatile IV *valuep;
46 atomic_t hysteresis;
43} async_t; 47} async_t;
44 48
45static AV *asyncs; 49static AV *asyncs;
46static async_t *sig_async [SIG_SIZE]; 50static async_t *sig_async [SIG_SIZE];
47 51
48#define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv)) 52#define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv))
49#define SvASYNC(rv) SvASYNC_nrv (SvRV (rv)) 53#define SvASYNC(rv) SvASYNC_nrv (SvRV (rv))
50 54
55static void async_signal (void *signal_arg, int value);
56
57static void
58setsig (int signum, void (*handler)(int))
59{
60#if _WIN32
61 signal (signum, handler);
62#else
63 struct sigaction sa;
64 sa.sa_handler = handler;
65 sigfillset (&sa.sa_mask);
66 sa.sa_flags = 0; /* if we interrupt a syscall, we might drain the pipe before it became ready */
67 sigaction (signum, &sa, 0);
68#endif
69}
70
71static void
72async_sigsend (int signum)
73{
74 async_signal (sig_async [signum], 0);
75}
76
51/* the main workhorse to signal */ 77/* the main workhorse to signal */
52static void 78static void
53async_signal (void *signal_arg, int value) 79async_signal (void *signal_arg, int value)
54{ 80{
55 static char pipedata [8]; 81 static char pipedata [8];
56 82
57 async_t *async = (async_t *)signal_arg; 83 async_t *async = (async_t *)signal_arg;
58 int pending = async->pending; 84 int pending = async->pending;
59 85
86 if (async->hysteresis)
87 setsig (async->signum, SIG_IGN);
88
60 *async->valuep = value ? value : 1; 89 *async->valuep = value ? value : 1;
90 ECB_MEMORY_FENCE_RELEASE;
61 async->pending = 1; 91 async->pending = 1;
92 ECB_MEMORY_FENCE_RELEASE;
62 async_pending = 1; 93 async_pending = 1;
94 ECB_MEMORY_FENCE_RELEASE;
95
96 if (!async->blocked)
97 {
63 psig_pend [9] = 1; 98 psig_pend [9] = 1;
99 ECB_MEMORY_FENCE_RELEASE;
64 *sig_pending = 1; 100 *sig_pending = 1;
101 ECB_MEMORY_FENCE_RELEASE;
102 }
65 103
66 if (!pending && async->fd_enable && async->ep.len) 104 if (!pending && async->fd_enable && async->ep.len)
67 s_epipe_signal (&async->ep); 105 s_epipe_signal (&async->ep);
68} 106}
69 107
74 int value = *async->valuep; 112 int value = *async->valuep;
75 113
76 *async->valuep = 0; 114 *async->valuep = 0;
77 async->pending = 0; 115 async->pending = 0;
78 116
117 /* restore signal */
118 if (async->hysteresis)
119 setsig (async->signum, async_sigsend);
120
79 /* drain pipe */ 121 /* drain pipe */
80 if (async->fd_enable && async->ep.len) 122 if (async->fd_enable && async->ep.len && async->autodrain)
81 s_epipe_drain (&async->ep); 123 s_epipe_drain (&async->ep);
82 124
83 if (async->c_cb) 125 if (async->c_cb)
84 { 126 {
85 dTHX; 127 dTHX;
131static void 173static void
132handle_asyncs (void) 174handle_asyncs (void)
133{ 175{
134 int i; 176 int i;
135 177
178 ECB_MEMORY_FENCE_ACQUIRE;
179
136 async_pending = 0; 180 async_pending = 0;
137 181
138 for (i = AvFILLp (asyncs); i >= 0; --i) 182 for (i = AvFILLp (asyncs); i >= 0; --i)
139 { 183 {
184 SV *async_sv = AvARRAY (asyncs)[i];
140 async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]); 185 async_t *async = SvASYNC_nrv (async_sv);
141 186
142 if (async->pending && !async->blocked) 187 if (async->pending && !async->blocked)
188 {
189 /* temporarily keep a refcount */
190 SvREFCNT_inc (async_sv);
143 handle_async (async); 191 handle_async (async);
192 SvREFCNT_dec (async_sv);
193
194 /* the handler could have deleted any number of asyncs */
195 if (i > AvFILLp (asyncs))
196 i = AvFILLp (asyncs);
197 }
144 } 198 }
145} 199}
146 200
147#if HAS_SA_SIGINFO 201#if HAS_SA_SIGINFO
148static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg) 202static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg)
160 else 214 else
161 old_sighandler (signum); 215 old_sighandler (signum);
162} 216}
163#endif 217#endif
164 218
165static void
166async_sigsend (int signum)
167{
168 async_signal (sig_async [signum], 0);
169}
170
171#define block(async) ++(async)->blocked 219#define block(async) ++(async)->blocked
172 220
173static void 221static void
174unblock (async_t *async) 222unblock (async_t *async)
175{ 223{
180 228
181static void 229static void
182scope_block_cb (pTHX_ void *async_sv) 230scope_block_cb (pTHX_ void *async_sv)
183{ 231{
184 async_t *async = SvASYNC_nrv ((SV *)async_sv); 232 async_t *async = SvASYNC_nrv ((SV *)async_sv);
233
234 async->scope_savestack = 0;
185 unblock (async); 235 unblock (async);
186 SvREFCNT_dec (async_sv); 236 SvREFCNT_dec (async_sv);
237}
238
239static void
240scope_block (SV *async_sv)
241{
242 async_t *async = SvASYNC_nrv (async_sv);
243
244 /* as a heuristic, we skip the scope block if we already are blocked */
245 /* and the existing scope block used the same savestack */
246
247 if (!async->scope_savestack || async->scope_savestack != PL_savestack)
248 {
249 async->scope_savestack = PL_savestack;
250 block (async);
251
252 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
253 SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv));
254 ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
255 }
187} 256}
188 257
189MODULE = Async::Interrupt PACKAGE = Async::Interrupt 258MODULE = Async::Interrupt PACKAGE = Async::Interrupt
190 259
191BOOT: 260BOOT:
201void 270void
202_alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue) 271_alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue)
203 PPCODE: 272 PPCODE:
204{ 273{
205 SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0; 274 SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0;
206 async_t *async; 275 async_t *async;
207 276
208 Newz (0, async, 1, async_t); 277 Newz (0, async, 1, async_t);
209 278
210 XPUSHs (sv_2mortal (newSViv (PTR2IV (async)))); 279 XPUSHs (sv_2mortal (newSViv (PTR2IV (async))));
211 /* TODO: need to bless right now to ensure deallocation */ 280 /* TODO: need to bless right now to ensure deallocation */
233 SvIOK_only (async->value); /* just to be sure */ 302 SvIOK_only (async->value); /* just to be sure */
234 SvREADONLY_on (async->value); 303 SvREADONLY_on (async->value);
235 304
236 async->valuep = &(SvIVX (async->value)); 305 async->valuep = &(SvIVX (async->value));
237 306
307 async->autodrain = 1;
238 async->cb = cv; 308 async->cb = cv;
239 async->c_cb = c_cb; 309 async->c_cb = c_cb;
240 async->c_arg = c_arg; 310 async->c_arg = c_arg;
241 async->signum = SvOK (signl) ? s_signum_croak (signl) : 0; 311 async->signum = SvOK (signl) ? s_signum_croak (signl) : 0;
242 312
244 { 314 {
245 if (async->signum < 0) 315 if (async->signum < 0)
246 croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl)); 316 croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl));
247 317
248 sig_async [async->signum] = async; 318 sig_async [async->signum] = async;
249#if _WIN32
250 signal (async->signum, async_sigsend); 319 setsig (async->signum, async_sigsend);
251#else
252 {
253 struct sigaction sa = { };
254 sa.sa_handler = async_sigsend;
255 sigfillset (&sa.sa_mask);
256 sigaction (async->signum, &sa, 0);
257 }
258#endif
259 } 320 }
260} 321}
322
323void
324signal_hysteresis (async_t *async, int enable)
325 CODE:
326 async->hysteresis = enable;
261 327
262void 328void
263signal_func (async_t *async) 329signal_func (async_t *async)
264 PPCODE: 330 PPCODE:
265 EXTEND (SP, 2); 331 EXTEND (SP, 2);
266 PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); 332 PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
267 PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); 333 PUSHs (sv_2mortal (newSViv (PTR2IV (async))));
268 334
335void
336scope_block_func (SV *self)
337 PPCODE:
338 EXTEND (SP, 2);
339 PUSHs (sv_2mortal (newSViv (PTR2IV (scope_block))));
340 PUSHs (sv_2mortal (newSViv (PTR2IV (SvRV (self)))));
341
269IV 342IV
270c_var (async_t *async) 343c_var (async_t *async)
271 CODE: 344 CODE:
272 RETVAL = PTR2IV (async->valuep); 345 RETVAL = PTR2IV (async->valuep);
273 OUTPUT: 346 OUTPUT:
274 RETVAL 347 RETVAL
275 348
276void 349void
350handle (async_t *async)
351 CODE:
352 handle_async (async);
353
354void
277signal (async_t *async, int value = 1) 355signal (async_t *async, int value = 1)
278 CODE: 356 CODE:
279 async_signal (async, value); 357 async_signal (async, value);
280 358
281void 359void
289 unblock (async); 367 unblock (async);
290 368
291void 369void
292scope_block (SV *self) 370scope_block (SV *self)
293 CODE: 371 CODE:
294{ 372 scope_block (SvRV (self));
295 SV *async_sv = SvRV (self);
296 async_t *async = SvASYNC_nrv (async_sv);
297 block (async);
298
299 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
300 SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv));
301 ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
302}
303 373
304void 374void
305pipe_enable (async_t *async) 375pipe_enable (async_t *async)
306 ALIAS: 376 ALIAS:
307 pipe_enable = 1 377 pipe_enable = 1
308 pipe_disable = 0 378 pipe_disable = 0
309 CODE: 379 CODE:
310 async->fd_enable = ix; 380 async->fd_enable = ix;
311 381
312int 382int
327 397
328 RETVAL = async->ep.fd [0]; 398 RETVAL = async->ep.fd [0];
329 OUTPUT: 399 OUTPUT:
330 RETVAL 400 RETVAL
331 401
402int
403pipe_autodrain (async_t *async, int enable = -1)
404 CODE:
405 RETVAL = async->autodrain;
406 if (enable >= 0)
407 async->autodrain = enable;
408 OUTPUT:
409 RETVAL
410
411void
412pipe_drain (async_t *async)
413 CODE:
414 if (async->ep.len)
415 s_epipe_drain (&async->ep);
332 416
333void 417void
334post_fork (async_t *async) 418post_fork (async_t *async)
335 CODE: 419 CODE:
336 if (async->ep.len) 420 if (async->ep.len)
337 { 421 {
338 int res; 422 int res;
339 423
340 /*block (async);*//*TODO*/ 424 /*block (async);*//*TODO*/
341 res = s_epipe_renew (&async->ep); 425 res = s_epipe_renew (&async->ep);
342 /*unblock (async);*//*TODO*/ 426 /*unblock (async);*//*TODO*/
343 427
347 431
348void 432void
349DESTROY (SV *self) 433DESTROY (SV *self)
350 CODE: 434 CODE:
351{ 435{
352 int i; 436 int i;
353 SV *async_sv = SvRV (self); 437 SV *async_sv = SvRV (self);
354 async_t *async = SvASYNC_nrv (async_sv); 438 async_t *async = SvASYNC_nrv (async_sv);
355 439
356 for (i = AvFILLp (asyncs); i >= 0; --i) 440 for (i = AvFILLp (asyncs); i >= 0; --i)
357 if (AvARRAY (asyncs)[i] == async_sv) 441 if (AvARRAY (asyncs)[i] == async_sv)
358 { 442 {
359 if (i < AvFILLp (asyncs))
360 AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)]; 443 AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)];
361 444 av_pop (asyncs);
362 assert (av_pop (asyncs) == async_sv);
363 goto found; 445 goto found;
364 } 446 }
365 447
366 if (!PL_dirty) 448 if (!PL_dirty)
367 warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report"); 449 warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report");
368 450
369 found: 451 found:
370 452
371 if (async->signum) 453 if (async->signum)
372 {
373#if _WIN32
374 signal (async->signum, SIG_DFL); 454 setsig (async->signum, SIG_DFL);
375#else
376 {
377 struct sigaction sa = { };
378 sa.sa_handler = SIG_DFL;
379 sigaction (async->signum, &sa, 0);
380 }
381#endif
382 }
383 455
384 if (!async->fh_r && async->ep.len) 456 if (!async->fh_r && async->ep.len)
385 s_epipe_destroy (&async->ep); 457 s_epipe_destroy (&async->ep);
386 458
387 SvREFCNT_dec (async->fh_r); 459 SvREFCNT_dec (async->fh_r);
390 SvREFCNT_dec (async->value); 462 SvREFCNT_dec (async->value);
391 463
392 Safefree (async); 464 Safefree (async);
393} 465}
394 466
467SV *
468sig2num (SV *signame_or_number)
469 ALIAS:
470 sig2num = 0
471 sig2name = 1
472 PROTOTYPE: $
473 CODE:
474{
475 int signum = s_signum (signame_or_number);
476
477 if (signum < 0)
478 RETVAL = &PL_sv_undef;
479 else if (ix)
480 RETVAL = newSVpv (PL_sig_name [signum], 0);
481 else
482 RETVAL = newSViv (signum);
483}
484 OUTPUT:
485 RETVAL
486
487MODULE = Async::Interrupt PACKAGE = Async::Interrupt::EventPipe PREFIX = s_epipe_
488
489void
490new (const char *klass)
491 PPCODE:
492{
493 s_epipe *epp;
494
495 Newz (0, epp, 1, s_epipe);
496 XPUSHs (sv_setref_iv (sv_newmortal (), klass, PTR2IV (epp)));
497
498 if (s_epipe_new (epp) < 0)
499 croak ("Async::Interrupt::EventPipe: unable to create new event pipe");
500}
501
502void
503filenos (s_epipe *epp)
504 PPCODE:
505 EXTEND (SP, 2);
506 PUSHs (sv_2mortal (newSViv (epp->fd [0])));
507 PUSHs (sv_2mortal (newSViv (epp->fd [1])));
508
509int
510fileno (s_epipe *epp)
511 ALIAS:
512 fileno = 0
513 fileno_r = 0
514 fileno_w = 1
515 CODE:
516 RETVAL = epp->fd [ix];
517 OUTPUT:
518 RETVAL
519
520int
521type (s_epipe *epp)
522 CODE:
523 RETVAL = epp->len;
524 OUTPUT:
525 RETVAL
526
527void
528s_epipe_signal (s_epipe *epp)
529
530void
531s_epipe_drain (s_epipe *epp)
532
533void
534signal_func (s_epipe *epp)
535 ALIAS:
536 drain_func = 1
537 PPCODE:
538 EXTEND (SP, 2);
539 PUSHs (sv_2mortal (newSViv (PTR2IV (ix ? s_epipe_drain : s_epipe_signal))));
540 PUSHs (sv_2mortal (newSViv (PTR2IV (epp))));
541
542void
543s_epipe_wait (s_epipe *epp)
544
545void
546DESTROY (s_epipe *epp)
547 CODE:
548 s_epipe_destroy (epp);
549

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines