ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/EV/EV.xs
Revision: 1.15
Committed: Fri May 23 00:27:06 2008 UTC (16 years ago) by root
Branch: MAIN
CVS Tags: rel-4_71, rel-4_72
Changes since 1.14: +14 -4 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 #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 && !ev_is_active (&idler))
54 ev_idle_start (EV_A, &idler);
55 else if (ev_is_active (&idler))
56 ev_idle_stop (EV_A, &idler);
57
58 --incede;
59 }
60
61 static void
62 readyhook (void)
63 {
64 ev_idle_start (EV_DEFAULT_UC, &idler);
65 }
66
67 /*****************************************************************************/
68
69 typedef struct
70 {
71 ev_io io;
72 ev_timer tw;
73 SV *done;
74 SV *current;
75 } coro_dir;
76
77 typedef struct
78 {
79 coro_dir r, w;
80 } coro_handle;
81
82
83 static int
84 handle_free (pTHX_ SV *sv, MAGIC *mg)
85 {
86 coro_handle *data = (coro_handle *)mg->mg_ptr;
87 mg->mg_ptr = 0;
88
89 ev_io_stop (EV_DEFAULT_UC, &data->r.io); ev_io_stop (EV_DEFAULT_UC, &data->w.io);
90 ev_timer_stop (EV_DEFAULT_UC, &data->r.tw); ev_timer_stop (EV_DEFAULT_UC, &data->w.tw);
91 SvREFCNT_dec (data->r.done); SvREFCNT_dec (data->w.done);
92 SvREFCNT_dec (data->r.current); SvREFCNT_dec (data->w.current);
93
94 return 0;
95 }
96
97 static MGVTBL handle_vtbl = { 0, 0, 0, 0, handle_free };
98
99 static void
100 handle_cb (coro_dir *dir, int done)
101 {
102 ev_io_stop (EV_DEFAULT_UC, &dir->io);
103 ev_timer_stop (EV_DEFAULT_UC, &dir->tw);
104
105 sv_setiv (dir->done, done);
106 SvREFCNT_dec (dir->done);
107 dir->done = 0;
108 CORO_READY (dir->current);
109 SvREFCNT_dec (dir->current);
110 dir->current = 0;
111 }
112
113 static void
114 handle_io_cb (EV_P_ ev_io *w, int revents)
115 {
116 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, io)), 1);
117 }
118
119 static void
120 handle_timer_cb (EV_P_ ev_timer *w, int revents)
121 {
122 handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, tw)), 0);
123 }
124
125 /*****************************************************************************/
126
127 MODULE = Coro::EV PACKAGE = Coro::EV
128
129 PROTOTYPES: ENABLE
130
131 BOOT:
132 {
133 I_EV_API ("Coro::EV");
134 I_CORO_API ("Coro::Event");
135
136 ev_prepare_init (&scheduler, prepare_cb);
137 ev_set_priority (&scheduler, EV_MINPRI);
138 ev_prepare_start (EV_DEFAULT, &scheduler);
139 ev_unref (EV_DEFAULT);
140
141 ev_idle_init (&idler, idle_cb);
142 ev_set_priority (&idler, EV_MINPRI);
143
144 CORO_READYHOOK = readyhook;
145 }
146
147 void
148 _loop_oneshot ()
149 CODE:
150 ++inhibit;
151 ev_loop (EV_DEFAULT, EVLOOP_ONESHOT);
152 --inhibit;
153
154 void
155 _timed_io_once (...)
156 CODE:
157 {
158 ONCE_INIT;
159 assert (AvFILLp (av) >= 1);
160 ev_once (
161 EV_DEFAULT,
162 sv_fileno (AvARRAY (av)[0]),
163 SvIV (AvARRAY (av)[1]),
164 AvFILLp (av) >= 2 && SvOK (AvARRAY (av)[2]) ? SvNV (AvARRAY (av)[2]) : -1.,
165 once_cb,
166 (void *)SvREFCNT_inc (av)
167 );
168 ONCE_DONE;
169 }
170
171 void
172 _timer_once (...)
173 CODE:
174 {
175 ONCE_INIT;
176 NV after = SvNV (AvARRAY (av)[0]);
177 ev_once (
178 EV_DEFAULT,
179 -1,
180 0,
181 after >= 0. ? after : 0.,
182 once_cb,
183 (void *)SvREFCNT_inc (av)
184 );
185 ONCE_DONE;
186 }
187
188 void
189 _readable_ev (SV *handle_sv, SV *done_sv)
190 ALIAS:
191 _writable_ev = 1
192 CODE:
193 {
194 AV *handle = (AV *)SvRV (handle_sv);
195 SV *data_sv = AvARRAY (handle)[5];
196 coro_handle *data;
197 coro_dir *dir;
198 assert (AvFILLp (handle) >= 7);
199
200 if (!SvOK (data_sv))
201 {
202 int fno = sv_fileno (AvARRAY (handle)[0]);
203 data_sv = AvARRAY (handle)[5] = NEWSV (0, sizeof (coro_handle));
204 SvPOK_only (data_sv);
205 SvREADONLY_on (data_sv);
206 data = (coro_handle *)SvPVX (data_sv);
207 memset (data, 0, sizeof (coro_handle));
208
209 ev_io_init (&data->r.io, handle_io_cb, fno, EV_READ);
210 ev_io_init (&data->w.io, handle_io_cb, fno, EV_WRITE);
211 ev_init (&data->r.tw, handle_timer_cb);
212 ev_init (&data->w.tw, handle_timer_cb);
213
214 sv_magicext (data_sv, 0, PERL_MAGIC_ext, &handle_vtbl, (char *)data, 0);
215 }
216 else
217 data = (coro_handle *)SvPVX (data_sv);
218
219 dir = ix ? &data->w : &data->r;
220
221 if (ev_is_active (&dir->io) || ev_is_active (&dir->tw))
222 croak ("recursive invocation of readable_ev or writable_ev");
223
224 dir->done = SvREFCNT_inc (done_sv);
225 dir->current = SvREFCNT_inc (CORO_CURRENT);
226
227 {
228 SV *to = AvARRAY (handle)[2];
229
230 if (SvOK (to))
231 {
232 ev_timer_set (&dir->tw, 0., SvNV (to));
233 ev_timer_again (EV_DEFAULT, &dir->tw);
234 }
235 }
236
237 ev_io_start (EV_DEFAULT, &dir->io);
238 }
239