ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Async-Interrupt/Interrupt.xs
Revision: 1.9
Committed: Fri Jul 17 01:51:32 2009 UTC (14 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-0_5
Changes since 1.8: +84 -25 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.7 volatile int blocked;
37 root 1.1
38 root 1.9 s_epipe ep;
39 root 1.6 int fd_wlen;
40     atomic_t fd_enable;
41 root 1.2 atomic_t pending;
42 root 1.9 volatile IV *valuep;
43 root 1.6 } async_t;
44    
45     static AV *asyncs;
46     static async_t *sig_async [SIG_SIZE];
47    
48     #define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv))
49     #define SvASYNC(rv) SvASYNC_nrv (SvRV (rv))
50 root 1.1
51     /* the main workhorse to signal */
52     static void
53     async_signal (void *signal_arg, int value)
54     {
55 root 1.6 static char pipedata [8];
56    
57     async_t *async = (async_t *)signal_arg;
58 root 1.2 int pending = async->pending;
59 root 1.1
60 root 1.9 *async->valuep = value ? value : 1;
61 root 1.2 async->pending = 1;
62     async_pending = 1;
63     psig_pend [9] = 1;
64     *sig_pending = 1;
65 root 1.1
66 root 1.7 {
67     int fd_enable = async->fd_enable;
68    
69 root 1.9 if (!pending && fd_enable && async->ep.fd [1] >= 0)
70     s_epipe_signal (&async->ep);
71 root 1.7 }
72 root 1.2 }
73    
74     static void
75 root 1.6 handle_async (async_t *async)
76 root 1.2 {
77     int old_errno = errno;
78 root 1.9 int value = *async->valuep;
79 root 1.2
80 root 1.9 *async->valuep = 0;
81 root 1.2 async->pending = 0;
82    
83     /* drain pipe */
84 root 1.9 if (async->fd_enable && async->ep.fd [0] >= 0)
85     s_epipe_drain (&async->ep);
86 root 1.2
87     if (async->c_cb)
88     {
89     dTHX;
90     async->c_cb (aTHX_ async->c_arg, value);
91     }
92    
93     if (async->cb)
94     {
95     dSP;
96    
97     SV *saveerr = SvOK (ERRSV) ? sv_mortalcopy (ERRSV) : 0;
98     SV *savedie = PL_diehook;
99    
100     PL_diehook = 0;
101    
102     PUSHSTACKi (PERLSI_SIGNAL);
103    
104     PUSHMARK (SP);
105     XPUSHs (sv_2mortal (newSViv (value)));
106     PUTBACK;
107     call_sv (async->cb, G_VOID | G_DISCARD | G_EVAL);
108    
109     if (SvTRUE (ERRSV))
110     {
111     SPAGAIN;
112    
113     PUSHMARK (SP);
114     PUTBACK;
115     call_sv (get_sv ("Async::Interrupt::DIED", 1), G_VOID | G_DISCARD | G_EVAL | G_KEEPERR);
116    
117     sv_setpvn (ERRSV, "", 0);
118     }
119    
120     if (saveerr)
121     sv_setsv (ERRSV, saveerr);
122 root 1.1
123 root 1.2 {
124     SV *oldhook = PL_diehook;
125     PL_diehook = savedie;
126     SvREFCNT_dec (oldhook);
127     }
128    
129     POPSTACK;
130 root 1.1 }
131    
132 root 1.2 errno = old_errno;
133 root 1.1 }
134    
135     static void
136 root 1.2 handle_asyncs (void)
137 root 1.1 {
138 root 1.2 int i;
139    
140 root 1.1 async_pending = 0;
141 root 1.2
142     for (i = AvFILLp (asyncs); i >= 0; --i)
143     {
144 root 1.6 async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]);
145 root 1.2
146     if (async->pending && !async->blocked)
147     handle_async (async);
148     }
149 root 1.1 }
150    
151 root 1.5 #if HAS_SA_SIGINFO
152 root 1.1 static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg)
153     {
154     if (signum == 9)
155 root 1.2 handle_asyncs ();
156 root 1.1 else
157     old_sighandler (signum, si, sarg);
158     }
159     #else
160 root 1.3 static Signal_t async_sighandler (int signum)
161 root 1.1 {
162     if (signum == 9)
163 root 1.3 handle_asyncs ();
164 root 1.1 else
165     old_sighandler (signum);
166     }
167     #endif
168    
169 root 1.4 static void
170 root 1.6 async_sigsend (int signum)
171     {
172     async_signal (sig_async [signum], 0);
173     }
174    
175 root 1.7 #define block(async) ++(async)->blocked
176    
177 root 1.6 static void
178 root 1.7 unblock (async_t *async)
179 root 1.4 {
180     --async->blocked;
181     if (async->pending && !async->blocked)
182     handle_async (async);
183 root 1.7 }
184 root 1.4
185 root 1.7 static void
186     scope_block_cb (pTHX_ void *async_sv)
187     {
188     async_t *async = SvASYNC_nrv ((SV *)async_sv);
189     unblock (async);
190 root 1.4 SvREFCNT_dec (async_sv);
191     }
192 root 1.1
193     MODULE = Async::Interrupt PACKAGE = Async::Interrupt
194    
195     BOOT:
196     old_sighandler = PL_sighandlerp;
197     PL_sighandlerp = async_sighandler;
198     sig_pending = &PL_sig_pending;
199     psig_pend = PL_psig_pend;
200     asyncs = newAV ();
201 root 1.4 CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */
202 root 1.1
203 root 1.3 PROTOTYPES: DISABLE
204    
205 root 1.6 void
206 root 1.9 _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue)
207 root 1.6 PPCODE:
208 root 1.1 {
209 root 1.8 SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0;
210 root 1.6 async_t *async;
211 root 1.1
212 root 1.6 Newz (0, async, 1, async_t);
213 root 1.1
214 root 1.6 XPUSHs (sv_2mortal (newSViv (PTR2IV (async))));
215 root 1.9 /* TODO: need to bless right now to ensure deallocation */
216 root 1.6 av_push (asyncs, TOPs);
217 root 1.2
218 root 1.9 SvGETMAGIC (fh_r); SvGETMAGIC (fh_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->ep.len = 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    
242 root 1.6 async->cb = cv;
243     async->c_cb = c_cb;
244     async->c_arg = c_arg;
245 root 1.8 async->signum = SvOK (signl) ? s_signum_croak (signl) : 0;
246 root 1.6
247     if (async->signum)
248     {
249     if (async->signum < 0)
250     croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl));
251    
252     sig_async [async->signum] = async;
253     #if _WIN32
254     signal (async->signum, async_sigsend);
255     #else
256     {
257     struct sigaction sa = { };
258     sa.sa_handler = async_sigsend;
259     sigfillset (&sa.sa_mask);
260     sigaction (async->signum, &sa, 0);
261     }
262     #endif
263     }
264 root 1.1 }
265    
266     void
267 root 1.6 signal_func (async_t *async)
268 root 1.1 PPCODE:
269     EXTEND (SP, 2);
270     PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
271 root 1.6 PUSHs (sv_2mortal (newSViv (PTR2IV (async))));
272 root 1.1
273 root 1.9 IV
274     c_var (async_t *async)
275     CODE:
276     RETVAL = PTR2IV (async->valuep);
277     OUTPUT:
278     RETVAL
279    
280 root 1.1 void
281 root 1.9 signal (async_t *async, int value = 1)
282 root 1.1 CODE:
283 root 1.6 async_signal (async, value);
284 root 1.2
285     void
286 root 1.6 block (async_t *async)
287 root 1.2 CODE:
288 root 1.7 block (async);
289 root 1.2
290     void
291 root 1.6 unblock (async_t *async)
292 root 1.2 CODE:
293 root 1.7 unblock (async);
294 root 1.1
295     void
296 root 1.4 scope_block (SV *self)
297     CODE:
298     {
299     SV *async_sv = SvRV (self);
300 root 1.6 async_t *async = SvASYNC_nrv (async_sv);
301 root 1.7 block (async);
302 root 1.4
303     LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
304     SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv));
305     ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
306     }
307    
308     void
309 root 1.6 pipe_enable (async_t *async)
310     ALIAS:
311     pipe_enable = 1
312     pipe_disable = 0
313     CODE:
314     async->fd_enable = ix;
315    
316 root 1.9 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     }
351    
352 root 1.6 void
353 root 1.1 DESTROY (SV *self)
354     CODE:
355     {
356     int i;
357     SV *async_sv = SvRV (self);
358 root 1.6 async_t *async = SvASYNC_nrv (async_sv);
359 root 1.1
360 root 1.2 for (i = AvFILLp (asyncs); i >= 0; --i)
361 root 1.1 if (AvARRAY (asyncs)[i] == async_sv)
362     {
363     if (i < AvFILLp (asyncs))
364 root 1.3 AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)];
365 root 1.1
366     assert (av_pop (asyncs) == async_sv);
367     goto found;
368     }
369    
370     if (!PL_dirty)
371 root 1.2 warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report");
372 root 1.1
373     found:
374 root 1.6
375     if (async->signum)
376     {
377     #if _WIN32
378     signal (async->signum, SIG_DFL);
379     #else
380     {
381     struct sigaction sa = { };
382     sa.sa_handler = SIG_DFL;
383     sigaction (async->signum, &sa, 0);
384     }
385     #endif
386     }
387    
388 root 1.9 if (!async->fh_r && async->ep.len)
389     s_epipe_destroy (&async->ep);
390    
391 root 1.2 SvREFCNT_dec (async->fh_r);
392     SvREFCNT_dec (async->fh_w);
393 root 1.1 SvREFCNT_dec (async->cb);
394 root 1.9 SvREFCNT_dec (async->value);
395 root 1.1
396     Safefree (async);
397     }
398