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.12 by root, Sat Jul 18 05:14:19 2009 UTC vs.
Revision 1.13 by root, Tue Jul 28 01:19:44 2009 UTC

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
46static AV *asyncs; 48static AV *asyncs;
47static async_t *sig_async [SIG_SIZE]; 49static 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
54static void async_signal (void *signal_arg, int value);
55
56static void
57setsig (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
69static void
70async_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 */
53static void 76static void
54async_signal (void *signal_arg, int value) 77async_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;
74 int old_errno = errno; 100 int old_errno = errno;
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;
105
106 /* restore signal */
107 if (async->hysteresis)
108 setsig (async->signum, async_sigsend);
79 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
171 else 201 else
172 old_sighandler (signum); 202 old_sighandler (signum);
173} 203}
174#endif 204#endif
175 205
176static void
177async_sigsend (int signum)
178{
179 async_signal (sig_async [signum], 0);
180}
181
182#define block(async) ++(async)->blocked 206#define block(async) ++(async)->blocked
183 207
184static void 208static void
185unblock (async_t *async) 209unblock (async_t *async)
186{ 210{
191 215
192static void 216static void
193scope_block_cb (pTHX_ void *async_sv) 217scope_block_cb (pTHX_ void *async_sv)
194{ 218{
195 async_t *async = SvASYNC_nrv ((SV *)async_sv); 219 async_t *async = SvASYNC_nrv ((SV *)async_sv);
220
221 async->scope_savestack = 0;
196 unblock (async); 222 unblock (async);
197 SvREFCNT_dec (async_sv); 223 SvREFCNT_dec (async_sv);
198} 224}
199 225
226static void
227scope_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
200MODULE = Async::Interrupt PACKAGE = Async::Interrupt 246MODULE = Async::Interrupt PACKAGE = Async::Interrupt
201 247
202BOOT: 248BOOT:
203 old_sighandler = PL_sighandlerp; 249 old_sighandler = PL_sighandlerp;
204 PL_sighandlerp = async_sighandler; 250 PL_sighandlerp = async_sighandler;
256 { 302 {
257 if (async->signum < 0) 303 if (async->signum < 0)
258 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));
259 305
260 sig_async [async->signum] = async; 306 sig_async [async->signum] = async;
261#if _WIN32
262 signal (async->signum, async_sigsend); 307 setsig (async->signum, async_sigsend);
263#else
264 {
265 struct sigaction sa;
266 sa.sa_handler = async_sigsend;
267 sigfillset (&sa.sa_mask);
268 sa.sa_flags = 0; /* if we interrupt a syscall, we might drain the pipe before it became ready */
269 sigaction (async->signum, &sa, 0);
270 }
271#endif
272 } 308 }
273} 309}
310
311void
312signal_hysteresis (async_t *async, int enable)
313 CODE:
314 async->hysteresis = enable;
274 315
275void 316void
276signal_func (async_t *async) 317signal_func (async_t *async)
277 PPCODE: 318 PPCODE:
278 EXTEND (SP, 2); 319 EXTEND (SP, 2);
279 PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); 320 PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
280 PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); 321 PUSHs (sv_2mortal (newSViv (PTR2IV (async))));
281 322
323void
324scope_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
282IV 330IV
283c_var (async_t *async) 331c_var (async_t *async)
284 CODE: 332 CODE:
285 RETVAL = PTR2IV (async->valuep); 333 RETVAL = PTR2IV (async->valuep);
286 OUTPUT: 334 OUTPUT:
302 unblock (async); 350 unblock (async);
303 351
304void 352void
305scope_block (SV *self) 353scope_block (SV *self)
306 CODE: 354 CODE:
307{ 355 scope_block (SvRV (self));
308 SV *async_sv = SvRV (self);
309 async_t *async = SvASYNC_nrv (async_sv);
310 block (async);
311
312 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
313 SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv));
314 ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
315}
316 356
317void 357void
318pipe_enable (async_t *async) 358pipe_enable (async_t *async)
319 ALIAS: 359 ALIAS:
320 pipe_enable = 1 360 pipe_enable = 1
386 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");
387 427
388 found: 428 found:
389 429
390 if (async->signum) 430 if (async->signum)
391 {
392#if _WIN32
393 signal (async->signum, SIG_DFL); 431 setsig (async->signum, SIG_DFL);
394#else
395 {
396 struct sigaction sa;
397 sa.sa_handler = SIG_DFL;
398 sigemptyset (&sa.sa_mask);
399 sa.sa_flags = 0;
400 sigaction (async->signum, &sa, 0);
401 }
402#endif
403 }
404 432
405 if (!async->fh_r && async->ep.len) 433 if (!async->fh_r && async->ep.len)
406 s_epipe_destroy (&async->ep); 434 s_epipe_destroy (&async->ep);
407 435
408 SvREFCNT_dec (async->fh_r); 436 SvREFCNT_dec (async->fh_r);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines