1 | #include "EXTERN.h" |
1 | #include "EXTERN.h" |
2 | #include "perl.h" |
2 | #include "perl.h" |
3 | #include "XSUB.h" |
3 | #include "XSUB.h" |
4 | |
4 | |
|
|
5 | #include <stddef.h> |
5 | #include <assert.h> |
6 | #include <assert.h> |
6 | #include <string.h> |
7 | #include <string.h> |
7 | |
8 | |
8 | #define EV_PROTOTYPES 0 |
9 | #define EV_PROTOTYPES 0 |
9 | #include "EVAPI.h" |
10 | #include "EVAPI.h" |
… | |
… | |
24 | static struct ev_prepare scheduler; |
25 | static struct ev_prepare scheduler; |
25 | static struct ev_idle idler; |
26 | static struct ev_idle idler; |
26 | static int inhibit; |
27 | static int inhibit; |
27 | |
28 | |
28 | static void |
29 | static void |
29 | idle_cb (struct ev_idle *w, int revents) |
30 | idle_cb (EV_P_ ev_idle *w, int revents) |
30 | { |
31 | { |
31 | ev_idle_stop (w); |
32 | ev_idle_stop (EV_A_ w); |
32 | } |
33 | } |
33 | |
34 | |
34 | static void |
35 | static void |
35 | prepare_cb (struct ev_prepare *w, int revents) |
36 | prepare_cb (EV_P_ ev_prepare *w, int revents) |
36 | { |
37 | { |
37 | static int incede; |
38 | static int incede; |
38 | |
39 | |
39 | if (inhibit) |
40 | if (inhibit) |
40 | return; |
41 | return; |
… | |
… | |
48 | |
49 | |
49 | /* if still ready, then we have lower-priority coroutines. |
50 | /* if still ready, then we have lower-priority coroutines. |
50 | * poll anyways, but do not block. |
51 | * poll anyways, but do not block. |
51 | */ |
52 | */ |
52 | if (CORO_NREADY >= incede && !ev_is_active (&idler)) |
53 | if (CORO_NREADY >= incede && !ev_is_active (&idler)) |
53 | ev_idle_start (&idler); |
54 | ev_idle_start (EV_A_ &idler); |
54 | |
55 | |
55 | --incede; |
56 | --incede; |
56 | } |
57 | } |
|
|
58 | |
|
|
59 | /*****************************************************************************/ |
|
|
60 | |
|
|
61 | typedef struct |
|
|
62 | { |
|
|
63 | ev_io io; |
|
|
64 | ev_timer tw; |
|
|
65 | SV *done; |
|
|
66 | SV *current; |
|
|
67 | } coro_dir; |
|
|
68 | |
|
|
69 | typedef struct |
|
|
70 | { |
|
|
71 | coro_dir r, w; |
|
|
72 | } coro_handle; |
|
|
73 | |
|
|
74 | |
|
|
75 | static int |
|
|
76 | handle_free (pTHX_ SV *sv, MAGIC *mg) |
|
|
77 | { |
|
|
78 | coro_handle *data = (coro_handle *)mg->mg_ptr; |
|
|
79 | mg->mg_ptr = 0; |
|
|
80 | |
|
|
81 | ev_io_stop (EV_DEFAULT_ &data->r.io); ev_io_stop (EV_DEFAULT_ &data->w.io); |
|
|
82 | ev_timer_stop (EV_DEFAULT_ &data->r.tw); ev_timer_stop (EV_DEFAULT_ &data->w.tw); |
|
|
83 | SvREFCNT_dec (data->r.done); SvREFCNT_dec (data->w.done); |
|
|
84 | SvREFCNT_dec (data->r.current); SvREFCNT_dec (data->w.current); |
|
|
85 | |
|
|
86 | return 0; |
|
|
87 | } |
|
|
88 | |
|
|
89 | static MGVTBL handle_vtbl = { 0, 0, 0, 0, handle_free }; |
|
|
90 | |
|
|
91 | static void |
|
|
92 | handle_cb (coro_dir *dir, int done) |
|
|
93 | { |
|
|
94 | ev_io_stop (EV_A_ &dir->io); |
|
|
95 | ev_timer_stop (EV_A_ &dir->tw); |
|
|
96 | |
|
|
97 | sv_setiv (dir->done, done); |
|
|
98 | SvREFCNT_dec (dir->done); |
|
|
99 | dir->done = 0; |
|
|
100 | CORO_READY (dir->current); |
|
|
101 | SvREFCNT_dec (dir->current); |
|
|
102 | dir->current = 0; |
|
|
103 | } |
|
|
104 | |
|
|
105 | static void |
|
|
106 | handle_io_cb (EV_P_ ev_io *w, int revents) |
|
|
107 | { |
|
|
108 | handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, io)), 1); |
|
|
109 | } |
|
|
110 | |
|
|
111 | static void |
|
|
112 | handle_timer_cb (EV_P_ ev_timer *w, int revents) |
|
|
113 | { |
|
|
114 | handle_cb ((coro_dir *)(((char *)w) - offsetof (coro_dir, tw)), 0); |
|
|
115 | } |
|
|
116 | |
|
|
117 | /*****************************************************************************/ |
57 | |
118 | |
58 | MODULE = Coro::EV PACKAGE = Coro::EV |
119 | MODULE = Coro::EV PACKAGE = Coro::EV |
59 | |
120 | |
60 | PROTOTYPES: ENABLE |
121 | PROTOTYPES: ENABLE |
61 | |
122 | |
… | |
… | |
63 | { |
124 | { |
64 | I_EV_API ("Coro::EV"); |
125 | I_EV_API ("Coro::EV"); |
65 | I_CORO_API ("Coro::Event"); |
126 | I_CORO_API ("Coro::Event"); |
66 | |
127 | |
67 | ev_prepare_init (&scheduler, prepare_cb); |
128 | ev_prepare_init (&scheduler, prepare_cb); |
|
|
129 | ev_set_priority (&scheduler, EV_MINPRI); |
68 | ev_prepare_start (EV_DEFAULT_ &scheduler); |
130 | ev_prepare_start (EV_DEFAULT_ &scheduler); |
69 | ev_unref (); |
131 | ev_unref (); |
70 | |
132 | |
71 | ev_idle_init (&idler, idle_cb); |
133 | ev_idle_init (&idler, idle_cb); |
|
|
134 | ev_set_priority (&idler, EV_MINPRI); |
72 | } |
135 | } |
73 | |
136 | |
74 | void |
137 | void |
75 | _loop_oneshot () |
138 | _loop_oneshot () |
76 | CODE: |
139 | CODE: |
… | |
… | |
108 | (void *)SvREFCNT_inc (av) |
171 | (void *)SvREFCNT_inc (av) |
109 | ); |
172 | ); |
110 | ONCE_DONE; |
173 | ONCE_DONE; |
111 | } |
174 | } |
112 | |
175 | |
|
|
176 | void |
|
|
177 | _readable_ev (SV *handle_sv, SV *done_sv) |
|
|
178 | ALIAS: |
|
|
179 | _writable_ev = 1 |
|
|
180 | CODE: |
|
|
181 | { |
|
|
182 | AV *handle = (AV *)SvRV (handle_sv); |
|
|
183 | SV *data_sv = AvARRAY (handle)[5]; |
|
|
184 | coro_handle *data; |
|
|
185 | coro_dir *dir; |
|
|
186 | assert (AvFILLp (handle) >= 7); |
113 | |
187 | |
|
|
188 | if (!SvOK (data_sv)) |
|
|
189 | { |
|
|
190 | int fno = sv_fileno (AvARRAY (handle)[0]); |
|
|
191 | data_sv = AvARRAY (handle)[5] = NEWSV (0, sizeof (coro_handle)); |
|
|
192 | SvPOK_only (data_sv); |
|
|
193 | SvREADONLY_on (data_sv); |
|
|
194 | data = (coro_handle *)SvPVX (data_sv); |
|
|
195 | memset (data, 0, sizeof (coro_handle)); |
114 | |
196 | |
|
|
197 | ev_io_init (&data->r.io, handle_io_cb, fno, EV_READ); |
|
|
198 | ev_io_init (&data->w.io, handle_io_cb, fno, EV_WRITE); |
|
|
199 | ev_init (&data->r.tw, handle_timer_cb); |
|
|
200 | ev_init (&data->w.tw, handle_timer_cb); |
|
|
201 | |
|
|
202 | sv_magicext (data_sv, 0, PERL_MAGIC_ext, &handle_vtbl, (char *)data, 0); |
|
|
203 | } |
|
|
204 | else |
|
|
205 | data = (coro_handle *)SvPVX (data_sv); |
|
|
206 | |
|
|
207 | dir = ix ? &data->w : &data->r; |
|
|
208 | |
|
|
209 | if (ev_is_active (&dir->io) || ev_is_active (&dir->tw)) |
|
|
210 | croak ("recursive invocation of readable_ev or writable_ev"); |
|
|
211 | |
|
|
212 | dir->done = SvREFCNT_inc (done_sv); |
|
|
213 | dir->current = SvREFCNT_inc (CORO_CURRENT); |
|
|
214 | |
|
|
215 | { |
|
|
216 | SV *to = AvARRAY (handle)[2]; |
|
|
217 | |
|
|
218 | if (SvOK (to)) |
|
|
219 | { |
|
|
220 | ev_timer_set (&dir->tw, 0., SvNV (to)); |
|
|
221 | ev_timer_start (EV_DEFAULT_ &dir->tw); |
|
|
222 | } |
|
|
223 | } |
|
|
224 | |
|
|
225 | ev_io_start (EV_DEFAULT_ &dir->io); |
|
|
226 | } |
|
|
227 | |