ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Async-Interrupt/Interrupt.xs
Revision: 1.11
Committed: Fri Jul 17 21:02:18 2009 UTC (17 years, 2 months ago) by root
Branch: MAIN
Changes since 1.10: +63 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.8 #include "schmorp.h"
6    
7 root 1.1 typedef volatile sig_atomic_t atomic_t;
8    
9     static int *sig_pending, *psig_pend; /* make local copies because of missing THX */
10     static Sighandler_t old_sighandler;
11     static atomic_t async_pending;
12    
13 root 1.5 #define PERL_VERSION_ATLEAST(a,b,c) \
14     (PERL_REVISION > (a) \
15     || (PERL_REVISION == (a) \
16     && (PERL_VERSION > (b) \
17     || (PERL_VERSION == (b) && PERL_SUBVERSION >= (c)))))
18    
19     #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
20     # define HAS_SA_SIGINFO 1
21     #endif
22    
23     #if !PERL_VERSION_ATLEAST(5,10,0)
24     # undef HAS_SA_SIGINFO
25     #endif
26    
27 root 1.6 /*****************************************************************************/
28 root 1.1
29 root 1.6 typedef struct {
30 root 1.1 SV *cb;
31 root 1.2 void (*c_cb)(pTHX_ void *c_arg, int value);
32     void *c_arg;
33     SV *fh_r, *fh_w;
34 root 1.9 SV *value;
35 root 1.6 int signum;
36 root 1.11 int autodrain;
37 root 1.7 volatile int blocked;
38 root 1.1
39 root 1.9 s_epipe ep;
40 root 1.6 int fd_wlen;
41     atomic_t fd_enable;
42 root 1.2 atomic_t pending;
43 root 1.9 volatile IV *valuep;
44 root 1.6 } async_t;
45    
46     static AV *asyncs;
47     static async_t *sig_async [SIG_SIZE];
48    
49     #define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv))
50     #define SvASYNC(rv) SvASYNC_nrv (SvRV (rv))
51 root 1.1
52     /* the main workhorse to signal */
53     static void
54     async_signal (void *signal_arg, int value)
55     {
56 root 1.6 static char pipedata [8];
57    
58     async_t *async = (async_t *)signal_arg;
59 root 1.2 int pending = async->pending;
60 root 1.1
61 root 1.9 *async->valuep = value ? value : 1;
62 root 1.2 async->pending = 1;
63     async_pending = 1;
64     psig_pend [9] = 1;
65     *sig_pending = 1;
66 root 1.1
67 root 1.10 if (!pending && async->fd_enable && async->ep.len)
68     s_epipe_signal (&async->ep);
69 root 1.2 }
70    
71     static void
72 root 1.6 handle_async (async_t *async)
73 root 1.2 {
74     int old_errno = errno;
75 root 1.9 int value = *async->valuep;
76 root 1.2
77 root 1.9 *async->valuep = 0;
78 root 1.2 async->pending = 0;
79    
80     /* drain pipe */
81 root 1.11 if (async->fd_enable && async->ep.len && async->autodrain)
82 root 1.9 s_epipe_drain (&async->ep);
83 root 1.2
84     if (async->c_cb)
85     {
86     dTHX;
87     async->c_cb (aTHX_ async->c_arg, value);
88     }
89    
90     if (async->cb)
91     {
92     dSP;
93    
94     SV *saveerr = SvOK (ERRSV) ? sv_mortalcopy (ERRSV) : 0;
95     SV *savedie = PL_diehook;
96    
97     PL_diehook = 0;
98    
99     PUSHSTACKi (PERLSI_SIGNAL);
100    
101     PUSHMARK (SP);
102     XPUSHs (sv_2mortal (newSViv (value)));
103     PUTBACK;
104     call_sv (async->cb, G_VOID | G_DISCARD | G_EVAL);
105    
106     if (SvTRUE (ERRSV))
107     {
108     SPAGAIN;
109    
110     PUSHMARK (SP);
111     PUTBACK;
112     call_sv (get_sv ("Async::Interrupt::DIED", 1), G_VOID | G_DISCARD | G_EVAL | G_KEEPERR);
113    
114     sv_setpvn (ERRSV, "", 0);
115     }
116    
117     if (saveerr)
118     sv_setsv (ERRSV, saveerr);
119 root 1.1
120 root 1.2 {
121     SV *oldhook = PL_diehook;
122     PL_diehook = savedie;
123     SvREFCNT_dec (oldhook);
124     }
125    
126     POPSTACK;
127 root 1.1 }
128    
129 root 1.2 errno = old_errno;
130 root 1.1 }
131    
132     static void
133 root 1.2 handle_asyncs (void)
134 root 1.1 {
135 root 1.2 int i;
136    
137 root 1.1 async_pending = 0;
138 root 1.2
139     for (i = AvFILLp (asyncs); i >= 0; --i)
140     {
141 root 1.6 async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]);
142 root 1.2
143     if (async->pending && !async->blocked)
144     handle_async (async);
145     }
146 root 1.1 }
147    
148 root 1.5 #if HAS_SA_SIGINFO
149 root 1.1 static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg)
150     {
151     if (signum == 9)
152 root 1.2 handle_asyncs ();
153 root 1.1 else
154     old_sighandler (signum, si, sarg);
155     }
156     #else
157 root 1.3 static Signal_t async_sighandler (int signum)
158 root 1.1 {
159     if (signum == 9)
160 root 1.3 handle_asyncs ();
161 root 1.1 else
162     old_sighandler (signum);
163     }
164     #endif
165    
166 root 1.4 static void
167 root 1.6 async_sigsend (int signum)
168     {
169     async_signal (sig_async [signum], 0);
170     }
171    
172 root 1.7 #define block(async) ++(async)->blocked
173    
174 root 1.6 static void
175 root 1.7 unblock (async_t *async)
176 root 1.4 {
177     --async->blocked;
178     if (async->pending && !async->blocked)
179     handle_async (async);
180 root 1.7 }
181 root 1.4
182 root 1.7 static void
183     scope_block_cb (pTHX_ void *async_sv)
184     {
185     async_t *async = SvASYNC_nrv ((SV *)async_sv);
186     unblock (async);
187 root 1.4 SvREFCNT_dec (async_sv);
188     }
189 root 1.1
190     MODULE = Async::Interrupt PACKAGE = Async::Interrupt
191    
192     BOOT:
193     old_sighandler = PL_sighandlerp;
194     PL_sighandlerp = async_sighandler;
195     sig_pending = &PL_sig_pending;
196     psig_pend = PL_psig_pend;
197     asyncs = newAV ();
198 root 1.4 CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */
199 root 1.1
200 root 1.3 PROTOTYPES: DISABLE
201    
202 root 1.6 void
203 root 1.9 _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue)
204 root 1.6 PPCODE:
205 root 1.1 {
206 root 1.8 SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0;
207 root 1.6 async_t *async;
208 root 1.1
209 root 1.6 Newz (0, async, 1, async_t);
210 root 1.1
211 root 1.6 XPUSHs (sv_2mortal (newSViv (PTR2IV (async))));
212 root 1.9 /* TODO: need to bless right now to ensure deallocation */
213 root 1.6 av_push (asyncs, TOPs);
214 root 1.2
215 root 1.9 SvGETMAGIC (fh_r); SvGETMAGIC (fh_w);
216     if (SvOK (fh_r) || SvOK (fh_w))
217     {
218     int fd_r = s_fileno_croak (fh_r, 0);
219     int fd_w = s_fileno_croak (fh_w, 1);
220    
221     async->fh_r = newSVsv (fh_r);
222     async->fh_w = newSVsv (fh_w);
223     async->ep.fd [0] = fd_r;
224     async->ep.fd [1] = fd_w;
225     async->ep.len = 1;
226     async->fd_enable = 1;
227     }
228    
229     async->value = SvROK (pvalue)
230     ? SvREFCNT_inc_NN (SvRV (pvalue))
231     : NEWSV (0, 0);
232    
233     sv_setiv (async->value, 0);
234     SvIOK_only (async->value); /* just to be sure */
235     SvREADONLY_on (async->value);
236    
237     async->valuep = &(SvIVX (async->value));
238    
239 root 1.11 async->autodrain = 1;
240 root 1.6 async->cb = cv;
241     async->c_cb = c_cb;
242     async->c_arg = c_arg;
243 root 1.8 async->signum = SvOK (signl) ? s_signum_croak (signl) : 0;
244 root 1.6
245     if (async->signum)
246     {
247     if (async->signum < 0)
248     croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl));
249    
250     sig_async [async->signum] = async;
251     #if _WIN32
252     signal (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     }
262 root 1.1 }
263    
264     void
265 root 1.6 signal_func (async_t *async)
266 root 1.1 PPCODE:
267     EXTEND (SP, 2);
268     PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
269 root 1.6 PUSHs (sv_2mortal (newSViv (PTR2IV (async))));
270 root 1.1
271 root 1.9 IV
272     c_var (async_t *async)
273     CODE:
274     RETVAL = PTR2IV (async->valuep);
275     OUTPUT:
276     RETVAL
277    
278 root 1.1 void
279 root 1.9 signal (async_t *async, int value = 1)
280 root 1.1 CODE:
281 root 1.6 async_signal (async, value);
282 root 1.2
283     void
284 root 1.6 block (async_t *async)
285 root 1.2 CODE:
286 root 1.7 block (async);
287 root 1.2
288     void
289 root 1.6 unblock (async_t *async)
290 root 1.2 CODE:
291 root 1.7 unblock (async);
292 root 1.1
293     void
294 root 1.4 scope_block (SV *self)
295     CODE:
296     {
297     SV *async_sv = SvRV (self);
298 root 1.6 async_t *async = SvASYNC_nrv (async_sv);
299 root 1.7 block (async);
300 root 1.4
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    
306     void
307 root 1.6 pipe_enable (async_t *async)
308     ALIAS:
309     pipe_enable = 1
310     pipe_disable = 0
311     CODE:
312     async->fd_enable = ix;
313    
314 root 1.9 int
315     pipe_fileno (async_t *async)
316     CODE:
317     if (!async->ep.len)
318     {
319     int res;
320    
321     /*block (async);*//*TODO*/
322     res = s_epipe_new (&async->ep);
323     async->fd_enable = 1;
324     /*unblock (async);*//*TODO*/
325    
326     if (res < 0)
327     croak ("Async::Interrupt: unable to initialize event pipe");
328     }
329    
330     RETVAL = async->ep.fd [0];
331     OUTPUT:
332     RETVAL
333    
334 root 1.11 int
335     pipe_autodrain (async_t *async, int enable = -1)
336     CODE:
337     RETVAL = async->autodrain;
338     if (enable >= 0)
339     async->autodrain = enable;
340     OUTPUT:
341     RETVAL
342 root 1.9
343     void
344     post_fork (async_t *async)
345     CODE:
346     if (async->ep.len)
347     {
348     int res;
349    
350     /*block (async);*//*TODO*/
351     res = s_epipe_renew (&async->ep);
352     /*unblock (async);*//*TODO*/
353    
354     if (res < 0)
355     croak ("Async::Interrupt: unable to initialize event pipe after fork");
356     }
357    
358 root 1.6 void
359 root 1.1 DESTROY (SV *self)
360     CODE:
361     {
362     int i;
363     SV *async_sv = SvRV (self);
364 root 1.6 async_t *async = SvASYNC_nrv (async_sv);
365 root 1.1
366 root 1.2 for (i = AvFILLp (asyncs); i >= 0; --i)
367 root 1.1 if (AvARRAY (asyncs)[i] == async_sv)
368     {
369     if (i < AvFILLp (asyncs))
370 root 1.3 AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)];
371 root 1.1
372     assert (av_pop (asyncs) == async_sv);
373     goto found;
374     }
375    
376     if (!PL_dirty)
377 root 1.2 warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report");
378 root 1.1
379     found:
380 root 1.6
381     if (async->signum)
382     {
383     #if _WIN32
384     signal (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    
394 root 1.9 if (!async->fh_r && async->ep.len)
395     s_epipe_destroy (&async->ep);
396    
397 root 1.2 SvREFCNT_dec (async->fh_r);
398     SvREFCNT_dec (async->fh_w);
399 root 1.1 SvREFCNT_dec (async->cb);
400 root 1.9 SvREFCNT_dec (async->value);
401 root 1.1
402     Safefree (async);
403     }
404    
405 root 1.11 MODULE = Async::Interrupt PACKAGE = Async::Interrupt::EventPipe PREFIX = s_epipe_
406    
407     void
408     new (const char *klass)
409     PPCODE:
410     {
411     s_epipe *epp;
412     SV *self;
413    
414     Newz (0, epp, 1, s_epipe);
415     XPUSHs (sv_setref_iv (sv_newmortal (), klass, PTR2IV (epp)));
416    
417     if (s_epipe_new (epp) < 0)
418     croak ("Async::Interrupt::EventPipe: unable to create new event pipe");
419     }
420    
421     void
422     filenos (s_epipe *epp)
423     PPCODE:
424     EXTEND (SP, 2);
425     PUSHs (sv_2mortal (newSViv (epp->fd [0])));
426     PUSHs (sv_2mortal (newSViv (epp->fd [1])));
427    
428     int
429     fileno (s_epipe *epp)
430     ALIAS:
431     fileno = 0
432     fileno_r = 0
433     fileno_w = 1
434     CODE:
435     RETVAL = epp->fd [ix];
436     OUTPUT:
437     RETVAL
438    
439     int
440     type (s_epipe *epp)
441     CODE:
442     RETVAL = epp->len;
443     OUTPUT:
444     RETVAL
445    
446     void
447     s_epipe_signal (s_epipe *epp)
448    
449     void
450     s_epipe_drain (s_epipe *epp)
451    
452     void
453     DESTROY (s_epipe *epp)
454     CODE:
455     s_epipe_destroy (epp);
456