ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/EV/EV.xs
Revision: 1.18
Committed: Fri Nov 14 23:48:10 2008 UTC (15 years, 6 months ago) by root
Branch: MAIN
Changes since 1.17: +172 -101 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.10 #include <stddef.h>
6 root 1.1 #include <assert.h>
7     #include <string.h>
8    
9     #include "EVAPI.h"
10     #include "../Coro/CoroAPI.h"
11    
12 root 1.2 static struct ev_prepare scheduler;
13     static struct ev_idle idler;
14 root 1.9 static int inhibit;
15 root 1.2
16     static void
17 root 1.10 idle_cb (EV_P_ ev_idle *w, int revents)
18 root 1.2 {
19 root 1.12 ev_idle_stop (EV_A, w);
20 root 1.2 }
21    
22     static void
23 root 1.10 prepare_cb (EV_P_ ev_prepare *w, int revents)
24 root 1.2 {
25 root 1.5 static int incede;
26    
27 root 1.9 if (inhibit)
28     return;
29    
30 root 1.5 ++incede;
31    
32     CORO_CEDE_NOTSELF;
33    
34 root 1.6 while (CORO_NREADY >= incede && CORO_CEDE)
35 root 1.2 ;
36    
37     /* if still ready, then we have lower-priority coroutines.
38 root 1.5 * poll anyways, but do not block.
39 root 1.2 */
40 root 1.16 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 root 1.5
51     --incede;
52 root 1.2 }
53    
54 root 1.15 static void
55     readyhook (void)
56     {
57 root 1.17 if (!ev_is_active (&idler))
58     ev_idle_start (EV_DEFAULT_UC, &idler);
59 root 1.15 }
60    
61 root 1.10 /*****************************************************************************/
62    
63 root 1.18 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     }
71    
72     static int
73     slf_check_once (pTHX_ struct CoroSLF *frame)
74     {
75     SV *data = (SV *)frame->data;
76    
77     if (SvROK (data))
78     return 1; /* repeat until we have been signalled */
79     else
80     {
81     dSP;
82    
83     XPUSHs (data);
84    
85     PUTBACK;
86     return 0;
87     }
88     }
89    
90     static void
91     slf_init_timed_io (aTHX_ struct CoroSLF *frame, SV **arg, int items)
92     {
93     SV *data;
94    
95     if (items < 2 || items > 3)
96     croak ("Coro::EV::timed_io_once requires exactly two or three parameters, not %d.\n", items);
97    
98     data = sv_2mortal (newRV_inc (CORO_CURRENT));
99     frame->data = (void *)data;
100     frame->prepare = GCoroAPI->prepare_schedule;
101     frame->check = slf_check_once;
102    
103     ev_once (
104     EV_DEFAULT_UC,
105     sv_fileno (arg [0]),
106     SvIV (arg [1]),
107     items >= 3 && SvOK (arg [2]) ? SvNV (arg [2]) : -1.,
108     once_cb,
109     data
110     );
111     }
112    
113     static void
114     slf_init_timer (aTHX_ struct CoroSLF *frame, SV **arg, int items)
115     {
116     SV *data;
117     NV after;
118    
119     if (items != 1)
120     croak ("Coro::EV::timer_once requires exactly one parameter, not %d.\n", items);
121    
122     data = sv_2mortal (newRV_inc (CORO_CURRENT));
123     frame->data = (void *)data;
124    
125     after = SvNV (arg [0]);
126    
127     ev_once (
128     EV_DEFAULT_UC,
129     -1,
130     0,
131     after >= 0. ? after : 0.,
132     once_cb,
133     data
134     );
135     }
136    
137     /*****************************************************************************/
138    
139 root 1.10 typedef struct
140     {
141     ev_io io;
142     ev_timer tw;
143 root 1.18 SV *data;
144 root 1.10 } coro_dir;
145    
146     typedef struct
147     {
148     coro_dir r, w;
149     } coro_handle;
150    
151     static int
152     handle_free (pTHX_ SV *sv, MAGIC *mg)
153     {
154     coro_handle *data = (coro_handle *)mg->mg_ptr;
155     mg->mg_ptr = 0;
156    
157 root 1.15 ev_io_stop (EV_DEFAULT_UC, &data->r.io); ev_io_stop (EV_DEFAULT_UC, &data->w.io);
158     ev_timer_stop (EV_DEFAULT_UC, &data->r.tw); ev_timer_stop (EV_DEFAULT_UC, &data->w.tw);
159 root 1.10
160     return 0;
161     }
162    
163     static MGVTBL handle_vtbl = { 0, 0, 0, 0, handle_free };
164    
165     static void
166 root 1.18 handle_cb (coro_dir *dir, int success)
167 root 1.10 {
168 root 1.15 ev_io_stop (EV_DEFAULT_UC, &dir->io);
169     ev_timer_stop (EV_DEFAULT_UC, &dir->tw);
170 root 1.10
171 root 1.18 CORO_READY (dir->data);
172     sv_setiv (dir->data, success);
173 root 1.10 }
174    
175     static void
176     handle_io_cb (EV_P_ ev_io *w, int revents)
177     {
178     handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, io)), 1);
179     }
180    
181     static void
182     handle_timer_cb (EV_P_ ev_timer *w, int revents)
183     {
184     handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, tw)), 0);
185     }
186    
187 root 1.18 static int
188     slf_check_rw (pTHX_ struct CoroSLF *frame)
189     {
190     SV *data = (SV *)frame->data;
191    
192     if (SvROK (data))
193     return 1;
194     else
195     {
196     dSP;
197    
198     XPUSHs (data);
199    
200     PUTBACK;
201     return 0;
202     }
203     }
204    
205     static void
206     slf_init_rw (aTHX_ struct CoroSLF *frame, SV *arg, int wr)
207     {
208     AV *handle = (AV *)SvRV (arg);
209     SV *data_sv = AvARRAY (handle)[5];
210     coro_handle *data;
211     coro_dir *dir;
212     assert (AvFILLp (handle) >= 7);
213    
214     if (!SvOK (data_sv))
215     {
216     int fno = sv_fileno (AvARRAY (handle)[0]);
217     data_sv = AvARRAY (handle)[5] = NEWSV (0, sizeof (coro_handle));
218     SvPOK_only (data_sv);
219     SvREADONLY_on (data_sv);
220     data = (coro_handle *)SvPVX (data_sv);
221     memset (data, 0, sizeof (coro_handle));
222    
223     ev_io_init (&data->r.io, handle_io_cb, fno, EV_READ);
224     ev_io_init (&data->w.io, handle_io_cb, fno, EV_WRITE);
225     ev_init (&data->r.tw, handle_timer_cb);
226     ev_init (&data->w.tw, handle_timer_cb);
227    
228     sv_magicext (data_sv, 0, PERL_MAGIC_ext, &handle_vtbl, (char *)data, 0);
229     }
230     else
231     data = (coro_handle *)SvPVX (data_sv);
232    
233     dir = wr ? &data->w : &data->r;
234    
235     if (ev_is_active (&dir->io) || ev_is_active (&dir->tw))
236     croak ("recursive invocation of readable_ev or writable_ev");
237    
238     dir->data = sv_2mortal (newRV_inc (CORO_CURRENT));
239    
240     {
241     SV *to = AvARRAY (handle)[2];
242    
243     if (SvOK (to))
244     {
245     ev_timer_set (&dir->tw, 0., SvNV (to));
246     ev_timer_again (EV_DEFAULT_UC, &dir->tw);
247     }
248     }
249    
250     ev_io_start (EV_DEFAULT_UC, &dir->io);
251    
252     frame->data = (void *)dir->data;
253     frame->prepare = GCoroAPI->prepare_schedule;
254     frame->check = slf_check_rw;
255     }
256    
257     static void
258     slf_init_readable (aTHX_ struct CoroSLF *frame, SV **arg, int items)
259     {
260     slf_init_rw (aTHX_ frame, arg [0], 0);
261     }
262    
263     static void
264     slf_init_writable (aTHX_ struct CoroSLF *frame, SV **arg, int items)
265     {
266     slf_init_rw (aTHX_ frame, arg [0], 1);
267     }
268    
269 root 1.10 /*****************************************************************************/
270    
271 root 1.1 MODULE = Coro::EV PACKAGE = Coro::EV
272    
273     PROTOTYPES: ENABLE
274    
275     BOOT:
276     {
277     I_EV_API ("Coro::EV");
278     I_CORO_API ("Coro::Event");
279 root 1.2
280 root 1.17 EV_DEFAULT; /* make sure it is initialised */
281    
282 root 1.3 ev_prepare_init (&scheduler, prepare_cb);
283 root 1.10 ev_set_priority (&scheduler, EV_MINPRI);
284 root 1.17 ev_prepare_start (EV_DEFAULT_UC, &scheduler);
285     ev_unref (EV_DEFAULT_UC);
286 root 1.2
287 root 1.3 ev_idle_init (&idler, idle_cb);
288 root 1.10 ev_set_priority (&idler, EV_MINPRI);
289 root 1.15
290     CORO_READYHOOK = readyhook;
291 root 1.1 }
292    
293     void
294 root 1.9 _loop_oneshot ()
295     CODE:
296 root 1.17 {
297     /* inhibit the prepare watcher, as we know we are the only
298     * ready coroutine and we don't want it to start an idle watcher
299     * just because of the fallback idle coro being of lower priority.
300     */
301 root 1.9 ++inhibit;
302 root 1.17
303     /* same reasoning as above, make sure it is stopped */
304     if (ev_is_active (&idler))
305     ev_idle_stop (EV_DEFAULT_UC, &idler);
306    
307     ev_loop (EV_DEFAULT_UC, EVLOOP_ONESHOT);
308    
309 root 1.9 --inhibit;
310 root 1.17 }
311 root 1.9
312     void
313 root 1.18 timed_io_once (...)
314 root 1.1 CODE:
315 root 1.18 CORO_EXECUTE_SLF_XS (slf_init_timed_io);
316 root 1.1
317     void
318 root 1.18 timer_once (...)
319 root 1.1 CODE:
320 root 1.18 CORO_EXECUTE_SLF_XS (slf_init_timer);
321 root 1.1
322 root 1.10 void
323 root 1.18 readable_ev (...)
324 root 1.10 CODE:
325 root 1.18 CORO_EXECUTE_SLF_XS (slf_init_readable);
326 root 1.1
327 root 1.18 void
328     writable_ev (...)
329     CODE:
330     CORO_EXECUTE_SLF_XS (slf_init_writable);
331 root 1.1