ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/EV/EV.xs
Revision: 1.40
Committed: Wed Oct 31 20:18:54 2012 UTC (11 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-6_32, rel-6_33, rel-6_31, rel-6_36, rel-6_37, rel-6_38, rel-6_39, rel-6_23, rel-6_29, rel-6_28, rel-6_46, rel-6_45, rel-6_43, rel-6_42, rel-6_41, rel-6_47, rel-6_44
Changes since 1.39: +0 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include <stddef.h>
6 #include <assert.h>
7 #include <string.h>
8
9 #include "EVAPI.h"
10 #include "../Coro/CoroAPI.h"
11
12 static struct ev_prepare scheduler;
13 static struct ev_idle idler;
14 static int inhibit;
15
16 static void
17 idle_cb (EV_P_ ev_idle *w, int revents)
18 {
19 ev_idle_stop (EV_A, w);
20 }
21
22 static void
23 prepare_cb (EV_P_ ev_prepare *w, int revents)
24 {
25 static int incede;
26
27 if (inhibit)
28 return;
29
30 ++incede;
31
32 CORO_CEDE_NOTSELF;
33
34 while (CORO_NREADY >= incede && CORO_CEDE)
35 ;
36
37 /* if still ready, then we have lower-priority coroutines.
38 * poll anyways, but do not block.
39 */
40 if (CORO_NREADY >= incede)
41 {
42 if (!ev_is_active (&idler))
43 ev_idle_start (EV_A, &idler);
44 }
45 else
46 {
47 if (ev_is_active (&idler))
48 ev_idle_stop (EV_A, &idler);
49 }
50
51 --incede;
52 }
53
54 static void
55 readyhook (void)
56 {
57 if (!ev_is_active (&idler))
58 ev_idle_start (EV_DEFAULT_UC, &idler);
59 }
60
61 /*****************************************************************************/
62
63 static void
64 once_cb (int revents, void *arg)
65 {
66 SV *data = (SV *)arg;
67
68 CORO_READY (data);
69 sv_setiv (data, revents);
70 SvREFCNT_dec (data);
71 }
72
73 static int
74 slf_check_once (pTHX_ struct CoroSLF *frame)
75 {
76 SV *data = (SV *)frame->data;
77
78 /* return early when an exception is pending */
79 if (CORO_THROW)
80 return 0;
81
82 if (SvROK (data))
83 return 1; /* repeat until we have been signalled */
84 else
85 {
86 dSP;
87
88 XPUSHs (data);
89
90 PUTBACK;
91 return 0;
92 }
93 }
94
95 static void
96 slf_init_timed_io (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
97 {
98 SV *data;
99
100 if (items < 2 || items > 3)
101 croak ("Coro::EV::timed_io_once requires exactly two or three parameters, not %d.\n", items);
102
103 SvGETMAGIC (arg [0]);
104 SvGETMAGIC (arg [1]);
105
106 if (items >= 3)
107 SvGETMAGIC (arg [2]);
108
109 data = sv_2mortal (newRV_inc (CORO_CURRENT));
110 frame->data = (void *)data;
111 frame->prepare = GCoroAPI->prepare_schedule;
112 frame->check = slf_check_once;
113
114 ev_once (
115 EV_DEFAULT_UC,
116 sv_fileno (arg [0]),
117 SvIV (arg [1]),
118 items >= 3 && SvOK (arg [2]) ? SvNV (arg [2]) : -1.,
119 once_cb,
120 SvREFCNT_inc (data)
121 );
122 }
123
124 static void
125 slf_init_timer (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
126 {
127 SV *data;
128 NV after;
129
130 if (items > 1)
131 croak ("Coro::EV::timer_once requires at most one parameter, not %d.\n", items);
132
133 data = sv_2mortal (newRV_inc (CORO_CURRENT));
134 frame->data = (void *)data;
135 frame->prepare = GCoroAPI->prepare_schedule;
136 frame->check = slf_check_once;
137
138 after = items ? SvNV (arg [0]) : 0;
139
140 ev_once (
141 EV_DEFAULT_UC,
142 -1,
143 0,
144 after >= 0. ? after : 0.,
145 once_cb,
146 SvREFCNT_inc (data)
147 );
148 }
149
150 /*****************************************************************************/
151
152 typedef struct
153 {
154 ev_io io;
155 ev_timer tw;
156 SV *data;
157 } coro_dir;
158
159 typedef struct
160 {
161 coro_dir r, w;
162 } coro_handle;
163
164 static int
165 handle_free (pTHX_ SV *sv, MAGIC *mg)
166 {
167 coro_handle *data = (coro_handle *)mg->mg_ptr;
168 mg->mg_ptr = 0;
169
170 ev_io_stop (EV_DEFAULT_UC, &data->r.io); ev_io_stop (EV_DEFAULT_UC, &data->w.io);
171 ev_timer_stop (EV_DEFAULT_UC, &data->r.tw); ev_timer_stop (EV_DEFAULT_UC, &data->w.tw);
172
173 return 0;
174 }
175
176 static MGVTBL handle_vtbl = { 0, 0, 0, 0, handle_free };
177
178 static void
179 handle_cb (coro_dir *dir, int success)
180 {
181 ev_io_stop (EV_DEFAULT_UC, &dir->io);
182 ev_timer_stop (EV_DEFAULT_UC, &dir->tw);
183
184 CORO_READY (dir->data);
185 sv_setiv (dir->data, success);
186 }
187
188 static void
189 handle_io_cb (EV_P_ ev_io *w, int revents)
190 {
191 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, io)), 1);
192 }
193
194 static void
195 handle_timer_cb (EV_P_ ev_timer *w, int revents)
196 {
197 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, tw)), 0);
198 }
199
200 static int
201 slf_check_rw (pTHX_ struct CoroSLF *frame)
202 {
203 SV *data = (SV *)frame->data;
204
205 /* return early when an exception is pending */
206 if (CORO_THROW)
207 return 0;
208
209 if (SvROK (data))
210 return 1;
211 else
212 {
213 dSP;
214
215 XPUSHs (data);
216
217 PUTBACK;
218 return 0;
219 }
220 }
221
222 static void
223 slf_init_rw (pTHX_ struct CoroSLF *frame, SV *arg, int wr)
224 {
225 AV *handle = (AV *)SvRV (arg);
226 SV *data_sv = AvARRAY (handle)[5];
227 coro_handle *data;
228 coro_dir *dir;
229 assert (AvFILLp (handle) >= 7);
230
231 if (!SvOK (data_sv))
232 {
233 int fno = sv_fileno (AvARRAY (handle)[0]);
234 data_sv = AvARRAY (handle)[5] = NEWSV (0, sizeof (coro_handle));
235 SvPOK_only (data_sv);
236 SvREADONLY_on (data_sv);
237 data = (coro_handle *)SvPVX (data_sv);
238 memset (data, 0, sizeof (coro_handle));
239
240 ev_io_init (&data->r.io, handle_io_cb, fno, EV_READ);
241 ev_io_init (&data->w.io, handle_io_cb, fno, EV_WRITE);
242 ev_init (&data->r.tw, handle_timer_cb);
243 ev_init (&data->w.tw, handle_timer_cb);
244
245 sv_magicext (data_sv, 0, PERL_MAGIC_ext, &handle_vtbl, (char *)data, 0);
246 }
247 else
248 data = (coro_handle *)SvPVX (data_sv);
249
250 dir = wr ? &data->w : &data->r;
251
252 if (ev_is_active (&dir->io) || ev_is_active (&dir->tw))
253 croak ("recursive invocation of readable_ev or writable_ev (concurrent Coro::Handle calls on same handle?), detected");
254
255 dir->data = sv_2mortal (newRV_inc (CORO_CURRENT));
256
257 {
258 SV *to = AvARRAY (handle)[2];
259
260 if (SvOK (to))
261 {
262 ev_timer_set (&dir->tw, 0., SvNV (to));
263 ev_timer_again (EV_DEFAULT_UC, &dir->tw);
264 }
265 }
266
267 ev_io_start (EV_DEFAULT_UC, &dir->io);
268
269 frame->data = (void *)dir->data;
270 frame->prepare = GCoroAPI->prepare_schedule;
271 frame->check = slf_check_rw;
272 }
273
274 static void
275 slf_init_readable (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
276 {
277 slf_init_rw (aTHX_ frame, arg [0], 0);
278 }
279
280 static void
281 slf_init_writable (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
282 {
283 slf_init_rw (aTHX_ frame, arg [0], 1);
284 }
285
286 /*****************************************************************************/
287
288 MODULE = Coro::EV PACKAGE = Coro::EV
289
290 PROTOTYPES: ENABLE
291
292 BOOT:
293 {
294 I_EV_API ("Coro::EV");
295 I_CORO_API ("Coro::EV");
296
297 EV_DEFAULT; /* make sure it is initialised */
298
299 ev_prepare_init (&scheduler, prepare_cb);
300 ev_set_priority (&scheduler, EV_MINPRI);
301 ev_prepare_start (EV_DEFAULT_UC, &scheduler);
302 ev_unref (EV_DEFAULT_UC);
303
304 ev_idle_init (&idler, idle_cb);
305 ev_set_priority (&idler, EV_MINPRI);
306
307 if (!CORO_READYHOOK) /* do not override if Coro::AnyEvent already did */
308 {
309 CORO_READYHOOK = readyhook;
310 CORO_READYHOOK (); /* make sure we don't miss previous ready's */
311 }
312 }
313
314 void
315 _set_readyhook ()
316 CODE:
317 CORO_READYHOOK = readyhook;
318 CORO_READYHOOK ();
319
320 void
321 _loop_oneshot ()
322 CODE:
323 {
324 /* inhibit the prepare watcher, as we know we are the only
325 * ready coroutine and we don't want it to start an idle watcher
326 * just because of the fallback idle coro being of lower priority.
327 */
328 ++inhibit;
329
330 /* same reasoning as above, make sure it is stopped */
331 if (ev_is_active (&idler))
332 ev_idle_stop (EV_DEFAULT_UC, &idler);
333 ev_run (EV_DEFAULT_UC, EVRUN_ONCE);
334 --inhibit;
335 }
336
337 void
338 timed_io_once (...)
339 PROTOTYPE: $$;$
340 CODE:
341 CORO_EXECUTE_SLF_XS (slf_init_timed_io);
342
343 void
344 timer_once (...)
345 PROTOTYPE: $
346 CODE:
347 CORO_EXECUTE_SLF_XS (slf_init_timer);
348
349 void
350 _poll (...)
351 PROTOTYPE:
352 CODE:
353 CORO_EXECUTE_SLF_XS (slf_init_timer);
354
355 PROTOTYPES: DISABLE
356
357 void
358 _readable_ev (...)
359 CODE:
360 items = 1; /* ignore the remaining args for speed inside Coro::Handle */
361 CORO_EXECUTE_SLF_XS (slf_init_readable);
362
363 void
364 _writable_ev (...)
365 CODE:
366 items = 1; /* ignore the remaining args for speed inside Coro::Handle */
367 CORO_EXECUTE_SLF_XS (slf_init_writable);
368