ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/EV/EV.xs
Revision: 1.17
Committed: Sun Jun 15 22:31:33 2008 UTC (15 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-4_91, rel-4_748, rel-4_8, rel-4_9, rel-4_743, rel-4_744, rel-4_747, rel-4_802, rel-4_803, rel-4_801, rel-4_804, rel-4_479, rel-4_745, rel-4_901, rel-4_746, rel-4_911, rel-4_912
Changes since 1.16: +25 -10 lines
Log Message:
4.743

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 #define EV_PROTOTYPES 0
10 #include "EVAPI.h"
11 #include "../Coro/CoroAPI.h"
12
13 static void
14 once_cb (int revents, void *arg)
15 {
16 AV *av = (AV *)arg; /* @_ */
17 av_push (av, newSViv (revents));
18 CORO_READY (AvARRAY (av)[0]);
19 SvREFCNT_dec (av);
20 }
21
22 #define ONCE_INIT AV *av = GvAV (PL_defgv)
23 #define ONCE_DONE av_clear (av); av_push (av, newRV_inc (CORO_CURRENT))
24
25 static struct ev_prepare scheduler;
26 static struct ev_idle idler;
27 static int inhibit;
28
29 static void
30 idle_cb (EV_P_ ev_idle *w, int revents)
31 {
32 ev_idle_stop (EV_A, w);
33 }
34
35 static void
36 prepare_cb (EV_P_ ev_prepare *w, int revents)
37 {
38 static int incede;
39
40 if (inhibit)
41 return;
42
43 ++incede;
44
45 CORO_CEDE_NOTSELF;
46
47 while (CORO_NREADY >= incede && CORO_CEDE)
48 ;
49
50 /* if still ready, then we have lower-priority coroutines.
51 * poll anyways, but do not block.
52 */
53 if (CORO_NREADY >= incede)
54 {
55 if (!ev_is_active (&idler))
56 ev_idle_start (EV_A, &idler);
57 }
58 else
59 {
60 if (ev_is_active (&idler))
61 ev_idle_stop (EV_A, &idler);
62 }
63
64 --incede;
65 }
66
67 static void
68 readyhook (void)
69 {
70 if (!ev_is_active (&idler))
71 ev_idle_start (EV_DEFAULT_UC, &idler);
72 }
73
74 /*****************************************************************************/
75
76 typedef struct
77 {
78 ev_io io;
79 ev_timer tw;
80 SV *done;
81 SV *current;
82 } coro_dir;
83
84 typedef struct
85 {
86 coro_dir r, w;
87 } coro_handle;
88
89
90 static int
91 handle_free (pTHX_ SV *sv, MAGIC *mg)
92 {
93 coro_handle *data = (coro_handle *)mg->mg_ptr;
94 mg->mg_ptr = 0;
95
96 ev_io_stop (EV_DEFAULT_UC, &data->r.io); ev_io_stop (EV_DEFAULT_UC, &data->w.io);
97 ev_timer_stop (EV_DEFAULT_UC, &data->r.tw); ev_timer_stop (EV_DEFAULT_UC, &data->w.tw);
98 SvREFCNT_dec (data->r.done); SvREFCNT_dec (data->w.done);
99 SvREFCNT_dec (data->r.current); SvREFCNT_dec (data->w.current);
100
101 return 0;
102 }
103
104 static MGVTBL handle_vtbl = { 0, 0, 0, 0, handle_free };
105
106 static void
107 handle_cb (coro_dir *dir, int done)
108 {
109 ev_io_stop (EV_DEFAULT_UC, &dir->io);
110 ev_timer_stop (EV_DEFAULT_UC, &dir->tw);
111
112 sv_setiv (dir->done, done);
113 SvREFCNT_dec (dir->done);
114 dir->done = 0;
115 CORO_READY (dir->current);
116 SvREFCNT_dec (dir->current);
117 dir->current = 0;
118 }
119
120 static void
121 handle_io_cb (EV_P_ ev_io *w, int revents)
122 {
123 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, io)), 1);
124 }
125
126 static void
127 handle_timer_cb (EV_P_ ev_timer *w, int revents)
128 {
129 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, tw)), 0);
130 }
131
132 /*****************************************************************************/
133
134 MODULE = Coro::EV PACKAGE = Coro::EV
135
136 PROTOTYPES: ENABLE
137
138 BOOT:
139 {
140 I_EV_API ("Coro::EV");
141 I_CORO_API ("Coro::Event");
142
143 EV_DEFAULT; /* make sure it is initialised */
144
145 ev_prepare_init (&scheduler, prepare_cb);
146 ev_set_priority (&scheduler, EV_MINPRI);
147 ev_prepare_start (EV_DEFAULT_UC, &scheduler);
148 ev_unref (EV_DEFAULT_UC);
149
150 ev_idle_init (&idler, idle_cb);
151 ev_set_priority (&idler, EV_MINPRI);
152
153 CORO_READYHOOK = readyhook;
154 }
155
156 void
157 _loop_oneshot ()
158 CODE:
159 {
160 /* inhibit the prepare watcher, as we know we are the only
161 * ready coroutine and we don't want it to start an idle watcher
162 * just because of the fallback idle coro being of lower priority.
163 */
164 ++inhibit;
165
166 /* same reasoning as above, make sure it is stopped */
167 if (ev_is_active (&idler))
168 ev_idle_stop (EV_DEFAULT_UC, &idler);
169
170 ev_loop (EV_DEFAULT_UC, EVLOOP_ONESHOT);
171
172 --inhibit;
173 }
174
175 void
176 _timed_io_once (...)
177 CODE:
178 {
179 ONCE_INIT;
180 assert (AvFILLp (av) >= 1);
181 ev_once (
182 EV_DEFAULT_UC,
183 sv_fileno (AvARRAY (av)[0]),
184 SvIV (AvARRAY (av)[1]),
185 AvFILLp (av) >= 2 && SvOK (AvARRAY (av)[2]) ? SvNV (AvARRAY (av)[2]) : -1.,
186 once_cb,
187 (void *)SvREFCNT_inc (av)
188 );
189 ONCE_DONE;
190 }
191
192 void
193 _timer_once (...)
194 CODE:
195 {
196 ONCE_INIT;
197 NV after = SvNV (AvARRAY (av)[0]);
198 ev_once (
199 EV_DEFAULT_UC,
200 -1,
201 0,
202 after >= 0. ? after : 0.,
203 once_cb,
204 (void *)SvREFCNT_inc (av)
205 );
206 ONCE_DONE;
207 }
208
209 void
210 _readable_ev (SV *handle_sv, SV *done_sv)
211 ALIAS:
212 _writable_ev = 1
213 CODE:
214 {
215 AV *handle = (AV *)SvRV (handle_sv);
216 SV *data_sv = AvARRAY (handle)[5];
217 coro_handle *data;
218 coro_dir *dir;
219 assert (AvFILLp (handle) >= 7);
220
221 if (!SvOK (data_sv))
222 {
223 int fno = sv_fileno (AvARRAY (handle)[0]);
224 data_sv = AvARRAY (handle)[5] = NEWSV (0, sizeof (coro_handle));
225 SvPOK_only (data_sv);
226 SvREADONLY_on (data_sv);
227 data = (coro_handle *)SvPVX (data_sv);
228 memset (data, 0, sizeof (coro_handle));
229
230 ev_io_init (&data->r.io, handle_io_cb, fno, EV_READ);
231 ev_io_init (&data->w.io, handle_io_cb, fno, EV_WRITE);
232 ev_init (&data->r.tw, handle_timer_cb);
233 ev_init (&data->w.tw, handle_timer_cb);
234
235 sv_magicext (data_sv, 0, PERL_MAGIC_ext, &handle_vtbl, (char *)data, 0);
236 }
237 else
238 data = (coro_handle *)SvPVX (data_sv);
239
240 dir = ix ? &data->w : &data->r;
241
242 if (ev_is_active (&dir->io) || ev_is_active (&dir->tw))
243 croak ("recursive invocation of readable_ev or writable_ev");
244
245 dir->done = SvREFCNT_inc (done_sv);
246 dir->current = SvREFCNT_inc (CORO_CURRENT);
247
248 {
249 SV *to = AvARRAY (handle)[2];
250
251 if (SvOK (to))
252 {
253 ev_timer_set (&dir->tw, 0., SvNV (to));
254 ev_timer_again (EV_DEFAULT_UC, &dir->tw);
255 }
256 }
257
258 ev_io_start (EV_DEFAULT_UC, &dir->io);
259 }
260