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.5 by root, Fri Jul 3 21:11:22 2009 UTC vs.
Revision 1.6 by root, Sat Jul 11 22:16:50 2009 UTC

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
25static int 28static int
26extract_fd (SV *fh, int wr) 29extract_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
54static AV *asyncs; 57#ifndef SIG_SIZE
58/* kudos to Slaven Rezic for the idea */
59static char sig_size [] = { SIG_NUM };
60# define SIG_SIZE (sizeof (sig_size) + 1)
61#endif
55 62
56struct async { 63static int
64sv_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
84typedef 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
99static AV *asyncs;
100static 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 */
69static void 106static void
70async_signal (void *signal_arg, int value) 107async_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
85static void 126static void
86handle_async (struct async *async) 127handle_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
184static void 225static void
226async_sigsend (int signum)
227{
228 async_signal (sig_async [signum], 0);
229}
230
231static void
185scope_block_cb (pTHX_ void *async_sv) 232scope_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
206PROTOTYPES: DISABLE 253PROTOTYPES: DISABLE
207 254
208SV * 255void
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
233void 298void
234signal_func (SV *self) 299signal_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
240void 305void
241signal (SV *self, int value = 0) 306signal (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
245void 310void
246block (SV *self) 311block (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
253void 315void
254unblock (SV *self) 316unblock (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
263void 322void
264scope_block (SV *self) 323scope_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
276void 335void
336pipe_enable (async_t *async)
337 ALIAS:
338 pipe_enable = 1
339 pipe_disable = 0
340 CODE:
341 async->fd_enable = ix;
342
343void
277DESTROY (SV *self) 344DESTROY (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);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines