… | |
… | |
20 | |
20 | |
21 | #if !PERL_VERSION_ATLEAST(5,10,0) |
21 | #if !PERL_VERSION_ATLEAST(5,10,0) |
22 | # undef HAS_SA_SIGINFO |
22 | # undef HAS_SA_SIGINFO |
23 | #endif |
23 | #endif |
24 | |
24 | |
|
|
25 | /*****************************************************************************/ |
|
|
26 | /* support stuff, copied from EV.xs mostly */ |
|
|
27 | |
25 | static int |
28 | static int |
26 | extract_fd (SV *fh, int wr) |
29 | extract_fd (SV *fh, int wr) |
27 | { |
30 | { |
28 | int fd = PerlIO_fileno (wr ? IoOFP (sv_2io (fh)) : IoIFP (sv_2io (fh))); |
31 | int fd = PerlIO_fileno (wr ? IoOFP (sv_2io (fh)) : IoIFP (sv_2io (fh))); |
29 | |
32 | |
… | |
… | |
49 | croak ("Async::Interrupt callback must be undef or a CODE reference"); |
52 | croak ("Async::Interrupt callback must be undef or a CODE reference"); |
50 | |
53 | |
51 | return (SV *)cv; |
54 | return (SV *)cv; |
52 | } |
55 | } |
53 | |
56 | |
54 | static AV *asyncs; |
57 | #ifndef SIG_SIZE |
|
|
58 | /* kudos to Slaven Rezic for the idea */ |
|
|
59 | static char sig_size [] = { SIG_NUM }; |
|
|
60 | # define SIG_SIZE (sizeof (sig_size) + 1) |
|
|
61 | #endif |
55 | |
62 | |
56 | struct async { |
63 | static int |
|
|
64 | sv_signum (SV *sig) |
|
|
65 | { |
|
|
66 | int signum; |
|
|
67 | |
|
|
68 | SvGETMAGIC (sig); |
|
|
69 | |
|
|
70 | for (signum = 1; signum < SIG_SIZE; ++signum) |
|
|
71 | if (strEQ (SvPV_nolen (sig), PL_sig_name [signum])) |
|
|
72 | return signum; |
|
|
73 | |
|
|
74 | signum = SvIV (sig); |
|
|
75 | |
|
|
76 | if (signum > 0 && signum < SIG_SIZE) |
|
|
77 | return signum; |
|
|
78 | |
|
|
79 | return -1; |
|
|
80 | } |
|
|
81 | |
|
|
82 | /*****************************************************************************/ |
|
|
83 | |
|
|
84 | typedef struct { |
57 | SV *cb; |
85 | SV *cb; |
58 | void (*c_cb)(pTHX_ void *c_arg, int value); |
86 | void (*c_cb)(pTHX_ void *c_arg, int value); |
59 | void *c_arg; |
87 | void *c_arg; |
60 | SV *fh_r, *fh_w; |
88 | SV *fh_r, *fh_w; |
61 | int blocked; |
89 | int blocked; |
|
|
90 | int signum; |
62 | |
91 | |
63 | int fd_r, fd_w; |
92 | int fd_r, fd_w; |
|
|
93 | int fd_wlen; |
|
|
94 | atomic_t fd_enable; |
64 | atomic_t value; |
95 | atomic_t value; |
65 | atomic_t pending; |
96 | atomic_t pending; |
66 | }; |
97 | } async_t; |
|
|
98 | |
|
|
99 | static AV *asyncs; |
|
|
100 | static async_t *sig_async [SIG_SIZE]; |
|
|
101 | |
|
|
102 | #define SvASYNC_nrv(sv) INT2PTR (async_t *, SvIVX (sv)) |
|
|
103 | #define SvASYNC(rv) SvASYNC_nrv (SvRV (rv)) |
67 | |
104 | |
68 | /* the main workhorse to signal */ |
105 | /* the main workhorse to signal */ |
69 | static void |
106 | static void |
70 | async_signal (void *signal_arg, int value) |
107 | async_signal (void *signal_arg, int value) |
71 | { |
108 | { |
|
|
109 | static char pipedata [8]; |
|
|
110 | |
72 | struct async *async = (struct async *)signal_arg; |
111 | async_t *async = (async_t *)signal_arg; |
73 | int pending = async->pending; |
112 | int pending = async->pending; |
74 | |
113 | |
75 | async->value = value; |
114 | async->value = value; |
76 | async->pending = 1; |
115 | async->pending = 1; |
77 | async_pending = 1; |
116 | async_pending = 1; |
78 | psig_pend [9] = 1; |
117 | psig_pend [9] = 1; |
79 | *sig_pending = 1; |
118 | *sig_pending = 1; |
80 | |
119 | |
81 | if (!pending && async->fd_w >= 0) |
120 | if (!pending && async->fd_w >= 0 && async->fd_enable) |
82 | write (async->fd_w, async, 1); |
121 | if (write (async->fd_w, pipedata, async->fd_wlen) < 0 && errno == EINVAL) |
|
|
122 | /* on EINVAL we assume it's an eventfd */ |
|
|
123 | write (async->fd_w, pipedata, (async->fd_wlen = 8)); |
83 | } |
124 | } |
84 | |
125 | |
85 | static void |
126 | static void |
86 | handle_async (struct async *async) |
127 | handle_async (async_t *async) |
87 | { |
128 | { |
88 | int old_errno = errno; |
129 | int old_errno = errno; |
89 | int value = async->value; |
130 | int value = async->value; |
90 | |
131 | |
91 | async->pending = 0; |
132 | async->pending = 0; |
92 | |
133 | |
93 | /* drain pipe */ |
134 | /* drain pipe */ |
94 | if (async->fd_r >= 0) |
135 | if (async->fd_r >= 0 && async->fd_enable) |
95 | { |
136 | { |
96 | char dummy [4]; |
137 | char dummy [9]; /* 9 is enough for eventfd and normal pipes */ |
97 | |
138 | |
98 | while (read (async->fd_r, dummy, sizeof (dummy)) == sizeof (dummy)) |
139 | while (read (async->fd_r, dummy, sizeof (dummy)) == sizeof (dummy)) |
99 | ; |
140 | ; |
100 | } |
141 | } |
101 | |
142 | |
… | |
… | |
154 | |
195 | |
155 | async_pending = 0; |
196 | async_pending = 0; |
156 | |
197 | |
157 | for (i = AvFILLp (asyncs); i >= 0; --i) |
198 | for (i = AvFILLp (asyncs); i >= 0; --i) |
158 | { |
199 | { |
159 | struct async *async = INT2PTR (struct async *, SvIVX (AvARRAY (asyncs)[i])); |
200 | async_t *async = SvASYNC_nrv (AvARRAY (asyncs)[i]); |
160 | |
201 | |
161 | if (async->pending && !async->blocked) |
202 | if (async->pending && !async->blocked) |
162 | handle_async (async); |
203 | handle_async (async); |
163 | } |
204 | } |
164 | } |
205 | } |
… | |
… | |
180 | old_sighandler (signum); |
221 | old_sighandler (signum); |
181 | } |
222 | } |
182 | #endif |
223 | #endif |
183 | |
224 | |
184 | static void |
225 | static void |
|
|
226 | async_sigsend (int signum) |
|
|
227 | { |
|
|
228 | async_signal (sig_async [signum], 0); |
|
|
229 | } |
|
|
230 | |
|
|
231 | static void |
185 | scope_block_cb (pTHX_ void *async_sv) |
232 | scope_block_cb (pTHX_ void *async_sv) |
186 | { |
233 | { |
187 | struct async *async = INT2PTR (struct async *, SvIVX ((SV *)async_sv)); |
234 | async_t *async = SvASYNC_nrv ((SV *)async_sv); |
188 | |
235 | |
189 | --async->blocked; |
236 | --async->blocked; |
190 | if (async->pending && !async->blocked) |
237 | if (async->pending && !async->blocked) |
191 | handle_async (async); |
238 | handle_async (async); |
192 | |
239 | |
… | |
… | |
203 | asyncs = newAV (); |
250 | asyncs = newAV (); |
204 | CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */ |
251 | CvNODEBUG_on (get_cv ("Async::Interrupt::scope_block", 0)); /* otherwise calling scope can be the debugger */ |
205 | |
252 | |
206 | PROTOTYPES: DISABLE |
253 | PROTOTYPES: DISABLE |
207 | |
254 | |
208 | SV * |
255 | void |
209 | _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w) |
256 | _alloc (SV *cb, void *c_cb, void *c_arg, SV *fh_r, SV *fh_w, SV *signl) |
210 | CODE: |
257 | PPCODE: |
211 | { |
258 | { |
212 | SV *cv = SvOK (cb) ? SvREFCNT_inc (get_cb (cb)) : 0; |
259 | SV *cv = SvOK (cb) ? SvREFCNT_inc (get_cb (cb)) : 0; |
213 | int fd_r = SvOK (fh_r) ? extract_fd (fh_r, 0) : -1; |
260 | int fd_r = SvOK (fh_r) ? extract_fd (fh_r, 0) : -1; |
214 | int fd_w = SvOK (fh_w) ? extract_fd (fh_w, 1) : -1; |
261 | int fd_w = SvOK (fh_w) ? extract_fd (fh_w, 1) : -1; |
215 | struct async *async; |
262 | async_t *async; |
216 | |
263 | |
217 | Newz (0, async, 1, struct async); |
264 | Newz (0, async, 1, async_t); |
218 | |
265 | |
|
|
266 | XPUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
|
|
267 | av_push (asyncs, TOPs); |
|
|
268 | |
219 | async->fh_r = fd_r >= 0 ? newSVsv (fh_r) : 0; async->fd_r = fd_r; |
269 | async->fh_r = fd_r >= 0 ? newSVsv (fh_r) : 0; async->fd_r = fd_r; |
220 | async->fh_w = fd_w >= 0 ? newSVsv (fh_w) : 0; async->fd_w = fd_w; |
270 | async->fh_w = fd_w >= 0 ? newSVsv (fh_w) : 0; async->fd_w = fd_w; |
|
|
271 | async->fd_wlen = 1; |
|
|
272 | async->fd_enable = 1; |
221 | async->cb = cv; |
273 | async->cb = cv; |
222 | async->c_cb = c_cb; |
274 | async->c_cb = c_cb; |
223 | async->c_arg = c_arg; |
275 | async->c_arg = c_arg; |
|
|
276 | SvGETMAGIC (signl); |
|
|
277 | async->signum = SvOK (signl) ? sv_signum (signl) : 0; |
224 | |
278 | |
225 | printf ("r,w %d,%d\n", fd_r, fd_w);//D |
279 | if (async->signum) |
|
|
280 | { |
|
|
281 | if (async->signum < 0) |
|
|
282 | croak ("Async::Interrupt::new got passed illegal signal name or number: %s", SvPV_nolen (signl)); |
226 | |
283 | |
227 | RETVAL = newSViv (PTR2IV (async)); |
284 | sig_async [async->signum] = async; |
228 | av_push (asyncs, RETVAL); |
285 | #if _WIN32 |
|
|
286 | signal (async->signum, async_sigsend); |
|
|
287 | #else |
|
|
288 | { |
|
|
289 | struct sigaction sa = { }; |
|
|
290 | sa.sa_handler = async_sigsend; |
|
|
291 | sigfillset (&sa.sa_mask); |
|
|
292 | sigaction (async->signum, &sa, 0); |
|
|
293 | } |
|
|
294 | #endif |
|
|
295 | } |
229 | } |
296 | } |
230 | OUTPUT: |
|
|
231 | RETVAL |
|
|
232 | |
297 | |
233 | void |
298 | void |
234 | signal_func (SV *self) |
299 | signal_func (async_t *async) |
235 | PPCODE: |
300 | PPCODE: |
236 | EXTEND (SP, 2); |
301 | EXTEND (SP, 2); |
237 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
302 | PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal)))); |
238 | PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (self))))); |
303 | PUSHs (sv_2mortal (newSViv (PTR2IV (async)))); |
239 | |
304 | |
240 | void |
305 | void |
241 | signal (SV *self, int value = 0) |
306 | signal (async_t *async, int value = 0) |
242 | CODE: |
307 | CODE: |
243 | async_signal (INT2PTR (void *, SvIVX (SvRV (self))), value); |
308 | async_signal (async, value); |
244 | |
309 | |
245 | void |
310 | void |
246 | block (SV *self) |
311 | block (async_t *async) |
247 | CODE: |
312 | CODE: |
248 | { |
|
|
249 | struct async *async = INT2PTR (struct async *, SvIVX (SvRV (self))); |
|
|
250 | ++async->blocked; |
313 | ++async->blocked; |
251 | } |
|
|
252 | |
314 | |
253 | void |
315 | void |
254 | unblock (SV *self) |
316 | unblock (async_t *async) |
255 | CODE: |
317 | CODE: |
256 | { |
|
|
257 | struct async *async = INT2PTR (struct async *, SvIVX (SvRV (self))); |
|
|
258 | --async->blocked; |
318 | --async->blocked; |
259 | if (async->pending && !async->blocked) |
319 | if (async->pending && !async->blocked) |
260 | handle_async (async); |
320 | handle_async (async); |
261 | } |
|
|
262 | |
321 | |
263 | void |
322 | void |
264 | scope_block (SV *self) |
323 | scope_block (SV *self) |
265 | CODE: |
324 | CODE: |
266 | { |
325 | { |
267 | SV *async_sv = SvRV (self); |
326 | SV *async_sv = SvRV (self); |
268 | struct async *async = INT2PTR (struct async *, SvIVX (async_sv)); |
327 | async_t *async = SvASYNC_nrv (async_sv); |
269 | ++async->blocked; |
328 | ++async->blocked; |
270 | |
329 | |
271 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
330 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
272 | SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv)); |
331 | SAVEDESTRUCTOR_X (scope_block_cb, (void *)SvREFCNT_inc (async_sv)); |
273 | ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
332 | ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
274 | } |
333 | } |
275 | |
334 | |
276 | void |
335 | void |
|
|
336 | pipe_enable (async_t *async) |
|
|
337 | ALIAS: |
|
|
338 | pipe_enable = 1 |
|
|
339 | pipe_disable = 0 |
|
|
340 | CODE: |
|
|
341 | async->fd_enable = ix; |
|
|
342 | |
|
|
343 | void |
277 | DESTROY (SV *self) |
344 | DESTROY (SV *self) |
278 | CODE: |
345 | CODE: |
279 | { |
346 | { |
280 | int i; |
347 | int i; |
281 | SV *async_sv = SvRV (self); |
348 | SV *async_sv = SvRV (self); |
282 | struct async *async = INT2PTR (struct async *, SvIVX (async_sv)); |
349 | async_t *async = SvASYNC_nrv (async_sv); |
283 | |
350 | |
284 | for (i = AvFILLp (asyncs); i >= 0; --i) |
351 | for (i = AvFILLp (asyncs); i >= 0; --i) |
285 | if (AvARRAY (asyncs)[i] == async_sv) |
352 | if (AvARRAY (asyncs)[i] == async_sv) |
286 | { |
353 | { |
287 | if (i < AvFILLp (asyncs)) |
354 | if (i < AvFILLp (asyncs)) |
… | |
… | |
293 | |
360 | |
294 | if (!PL_dirty) |
361 | if (!PL_dirty) |
295 | warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report"); |
362 | warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report"); |
296 | |
363 | |
297 | found: |
364 | found: |
|
|
365 | |
|
|
366 | if (async->signum) |
|
|
367 | { |
|
|
368 | #if _WIN32 |
|
|
369 | signal (async->signum, SIG_DFL); |
|
|
370 | #else |
|
|
371 | { |
|
|
372 | struct sigaction sa = { }; |
|
|
373 | sa.sa_handler = SIG_DFL; |
|
|
374 | sigaction (async->signum, &sa, 0); |
|
|
375 | } |
|
|
376 | #endif |
|
|
377 | } |
|
|
378 | |
298 | SvREFCNT_dec (async->fh_r); |
379 | SvREFCNT_dec (async->fh_r); |
299 | SvREFCNT_dec (async->fh_w); |
380 | SvREFCNT_dec (async->fh_w); |
300 | SvREFCNT_dec (async->cb); |
381 | SvREFCNT_dec (async->cb); |
301 | |
382 | |
302 | Safefree (async); |
383 | Safefree (async); |