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.11 by root, Fri Jul 17 21:02:18 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;
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
149static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg) 189static 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
166static void
167async_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
174static void 208static void
175unblock (async_t *async) 209unblock (async_t *async)
176{ 210{
181 215
182static void 216static void
183scope_block_cb (pTHX_ void *async_sv) 217scope_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
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
190MODULE = Async::Interrupt PACKAGE = Async::Interrupt 246MODULE = Async::Interrupt PACKAGE = Async::Interrupt
191 247
192BOOT: 248BOOT:
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
311void
312signal_hysteresis (async_t *async, int enable)
313 CODE:
314 async->hysteresis = enable;
263 315
264void 316void
265signal_func (async_t *async) 317signal_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
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
271IV 330IV
272c_var (async_t *async) 331c_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
293void 352void
294scope_block (SV *self) 353scope_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
306void 357void
307pipe_enable (async_t *async) 358pipe_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);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines