ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Async-Interrupt/Interrupt.xs
Revision: 1.10
Committed: Fri Jul 17 03:32:29 2009 UTC (14 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-0_501
Changes since 1.9: +3 -7 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include "schmorp.h"
6
7 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 #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 /*****************************************************************************/
28
29 typedef struct {
30 SV *cb;
31 void (*c_cb)(pTHX_ void *c_arg, int value);
32 void *c_arg;
33 SV *fh_r, *fh_w;
34 SV *value;
35 int signum;
36 volatile int blocked;
37
38 s_epipe ep;
39 int fd_wlen;
40 atomic_t fd_enable;
41 atomic_t pending;
42 volatile IV *valuep;
43 } 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
51 /* the main workhorse to signal */
52 static void
53 async_signal (void *signal_arg, int value)
54 {
55 static char pipedata [8];
56
57 async_t *async = (async_t *)signal_arg;
58 int pending = async->pending;
59
60 *async->valuep = value ? value : 1;
61 async->pending = 1;
62 async_pending = 1;
63 psig_pend [9] = 1;
64 *sig_pending = 1;
65
66 if (!pending && async->fd_enable && async->ep.len)
67 s_epipe_signal (&async->ep);
68 }
69
70 static void
71 handle_async (async_t *async)
72 {
73 int old_errno = errno;
74 int value = *async->valuep;
75
76 *async->valuep = 0;
77 async->pending = 0;
78
79 /* drain pipe */
80 if (async->fd_enable && async->ep.len)
81 s_epipe_drain (&async->ep);
82
83 if (async->c_cb)
84 {
85 dTHX;
86 async->c_cb (aTHX_ async->c_arg, value);
87 }
88
89 if (async->cb)
90 {
91 dSP;
92
93 SV *saveerr = SvOK (ERRSV) ? sv_mortalcopy (ERRSV) : 0;
94 SV *savedie = PL_diehook;
95
96 PL_diehook = 0;
97
98 PUSHSTACKi (PERLSI_SIGNAL);
99
100 PUSHMARK (SP);
101 XPUSHs (sv_2mortal (newSViv (value)));
102 PUTBACK;
103 call_sv (async->cb, G_VOID | G_DISCARD | G_EVAL);
104
105 if (SvTRUE (ERRSV))
106 {
107 SPAGAIN;
108
109 PUSHMARK (SP);
110 PUTBACK;
111 call_sv (get_sv ("Async::Interrupt::DIED", 1), G_VOID | G_DISCARD | G_EVAL | G_KEEPERR);
112
113 sv_setpvn (ERRSV, "", 0);
114 }
115
116 if (saveerr)
117 sv_setsv (ERRSV, saveerr);
118
119 {
120 SV *oldhook = PL_diehook;
121 PL_diehook = savedie;
122 SvREFCNT_dec (oldhook);
123 }
124
125 POPSTACK;
126 }
127
128 errno = old_errno;
129 }
130
131 static void
132 handle_asyncs (void)
133 {
134 int i;
135
136 async_pending = 0;
137
138 for (i = AvFILLp (asyncs); i >= 0; --i)
139 {
140 async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]);
141
142 if (async->pending && !async->blocked)
143 handle_async (async);
144 }
145 }
146
147 #if HAS_SA_SIGINFO
148 static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg)
149 {
150 if (signum == 9)
151 handle_asyncs ();
152 else
153 old_sighandler (signum, si, sarg);
154 }
155 #else
156 static Signal_t async_sighandler (int signum)
157 {
158 if (signum == 9)
159 handle_asyncs ();
160 else
161 old_sighandler (signum);
162 }
163 #endif
164
165 static void
166 async_sigsend (int signum)
167 {
168 async_signal (sig_async [signum], 0);
169 }
170
171 #define block(async) ++(async)->blocked
172
173 static void
174 unblock (async_t *async)
175 {
176 --async->blocked;
177 if (async->pending && !async->blocked)
178 handle_async (async);
179 }
180
181 static void
182 scope_block_cb (pTHX_ void *async_sv)
183 {
184 async_t *async = SvASYNC_nrv ((SV *)async_sv);
185 unblock (async);
186 SvREFCNT_dec (async_sv);
187 }
188
189 MODULE = Async::Interrupt PACKAGE = Async::Interrupt
190
191 BOOT:
192 old_sighandler = PL_sighandlerp;
193 PL_sighandlerp = async_sighandler;
194 sig_pending = &PL_sig_pending;
195 psig_pend = PL_psig_pend;
196 asyncs = newAV ();
197 CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */
198
199 PROTOTYPES: DISABLE
200
201 void
202 _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl, SV *pvalue)
203 PPCODE:
204 {
205 SV *cv = SvOK (cb) ? SvREFCNT_inc (s_get_cv_croak (cb)) : 0;
206 async_t *async;
207
208 Newz (0, async, 1, async_t);
209
210 XPUSHs (sv_2mortal (newSViv (PTR2IV (async))));
211 /* TODO: need to bless right now to ensure deallocation */
212 av_push (asyncs, TOPs);
213
214 SvGETMAGIC (fh_r); SvGETMAGIC (fh_w);
215 if (SvOK (fh_r) || SvOK (fh_w))
216 {
217 int fd_r = s_fileno_croak (fh_r, 0);
218 int fd_w = s_fileno_croak (fh_w, 1);
219
220 async->fh_r = newSVsv (fh_r);
221 async->fh_w = newSVsv (fh_w);
222 async->ep.fd [0] = fd_r;
223 async->ep.fd [1] = fd_w;
224 async->ep.len = 1;
225 async->fd_enable = 1;
226 }
227
228 async->value = SvROK (pvalue)
229 ? SvREFCNT_inc_NN (SvRV (pvalue))
230 : NEWSV (0, 0);
231
232 sv_setiv (async->value, 0);
233 SvIOK_only (async->value); /* just to be sure */
234 SvREADONLY_on (async->value);
235
236 async->valuep = &(SvIVX (async->value));
237
238 async->cb = cv;
239 async->c_cb = c_cb;
240 async->c_arg = c_arg;
241 async->signum = SvOK (signl) ? s_signum_croak (signl) : 0;
242
243 if (async->signum)
244 {
245 if (async->signum < 0)
246 croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl));
247
248 sig_async [async->signum] = async;
249 #if _WIN32
250 signal (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 }
260 }
261
262 void
263 signal_func (async_t *async)
264 PPCODE:
265 EXTEND (SP, 2);
266 PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
267 PUSHs (sv_2mortal (newSViv (PTR2IV (async))));
268
269 IV
270 c_var (async_t *async)
271 CODE:
272 RETVAL = PTR2IV (async->valuep);
273 OUTPUT:
274 RETVAL
275
276 void
277 signal (async_t *async, int value = 1)
278 CODE:
279 async_signal (async, value);
280
281 void
282 block (async_t *async)
283 CODE:
284 block (async);
285
286 void
287 unblock (async_t *async)
288 CODE:
289 unblock (async);
290
291 void
292 scope_block (SV *self)
293 CODE:
294 {
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
304 void
305 pipe_enable (async_t *async)
306 ALIAS:
307 pipe_enable = 1
308 pipe_disable = 0
309 CODE:
310 async->fd_enable = ix;
311
312 int
313 pipe_fileno (async_t *async)
314 CODE:
315 if (!async->ep.len)
316 {
317 int res;
318
319 /*block (async);*//*TODO*/
320 res = s_epipe_new (&async->ep);
321 async->fd_enable = 1;
322 /*unblock (async);*//*TODO*/
323
324 if (res < 0)
325 croak ("Async::Interrupt: unable to initialize event pipe");
326 }
327
328 RETVAL = async->ep.fd [0];
329 OUTPUT:
330 RETVAL
331
332
333 void
334 post_fork (async_t *async)
335 CODE:
336 if (async->ep.len)
337 {
338 int res;
339
340 /*block (async);*//*TODO*/
341 res = s_epipe_renew (&async->ep);
342 /*unblock (async);*//*TODO*/
343
344 if (res < 0)
345 croak ("Async::Interrupt: unable to initialize event pipe after fork");
346 }
347
348 void
349 DESTROY (SV *self)
350 CODE:
351 {
352 int i;
353 SV *async_sv = SvRV (self);
354 async_t *async = SvASYNC_nrv (async_sv);
355
356 for (i = AvFILLp (asyncs); i >= 0; --i)
357 if (AvARRAY (asyncs)[i] == async_sv)
358 {
359 if (i < AvFILLp (asyncs))
360 AvARRAY (asyncs)[i] = AvARRAY (asyncs)[AvFILLp (asyncs)];
361
362 assert (av_pop (asyncs) == async_sv);
363 goto found;
364 }
365
366 if (!PL_dirty)
367 warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report");
368
369 found:
370
371 if (async->signum)
372 {
373 #if _WIN32
374 signal (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
384 if (!async->fh_r && async->ep.len)
385 s_epipe_destroy (&async->ep);
386
387 SvREFCNT_dec (async->fh_r);
388 SvREFCNT_dec (async->fh_w);
389 SvREFCNT_dec (async->cb);
390 SvREFCNT_dec (async->value);
391
392 Safefree (async);
393 }
394