1 static struct pe_watcher_vtbl pe_io_vtbl;
2
3 static pe_ring IOWatch;
4 static int IOWatchCount;
5 static int IOWatch_OK;
6
7 static void pe_sys_io_add (pe_io *ev);
8 static void pe_sys_io_del (pe_io *ev);
9
pe_io_allocate(HV * stash,SV * temple)10 static pe_watcher *pe_io_allocate(HV *stash, SV *temple) {
11 pe_io *ev;
12 EvNew(4, ev, 1, pe_io);
13 ev->base.vtbl = &pe_io_vtbl;
14 pe_watcher_init(&ev->base, stash, temple);
15 PE_RING_INIT(&ev->tm.ring, ev);
16 PE_RING_INIT(&ev->ioring, ev);
17 ev->fd = -1;
18 ev->timeout = 0;
19 ev->handle = &PL_sv_undef;
20 ev->poll = PE_R;
21 ev->tm_callback = 0;
22 ev->tm_ext_data = 0;
23 WaINVOKE1_off(ev);
24 WaREPEAT_on(ev);
25 return (pe_watcher*) ev;
26 }
27
pe_io_dtor(pe_watcher * _ev)28 static void pe_io_dtor(pe_watcher *_ev) {
29 pe_io *ev = (pe_io*) _ev;
30 if (WaTMPERLCB(ev))
31 SvREFCNT_dec(ev->tm_callback);
32 PE_RING_DETACH(&ev->ioring);
33 SvREFCNT_dec(ev->handle);
34 pe_watcher_dtor(_ev);
35 EvFree(4, _ev);
36 }
37
pe_io_start(pe_watcher * _ev,int repeat)38 static char *pe_io_start(pe_watcher *_ev, int repeat) {
39 STRLEN n_a;
40 int ok=0;
41 pe_io *ev = (pe_io*) _ev;
42 if (SvOK(ev->handle))
43 ev->fd = pe_sys_fileno(ev->handle, SvPV(ev->base.desc, n_a));
44
45 /* On Unix, it is possible to set the 'fd' in C code without
46 assigning anything to the 'handle'. This should be more
47 officially supported but maybe it is too unix specific. */
48
49 if (ev->fd >= 0 && (ev->poll & ~PE_T)) {
50 if (!ev->base.callback)
51 return "without io callback";
52 PE_RING_UNSHIFT(&ev->ioring, &IOWatch);
53 pe_sys_io_add(ev);
54 ++IOWatchCount;
55 IOWatch_OK = 0;
56 ++ok;
57 }
58 if (ev->timeout) {
59 if (!ev->base.callback && !ev->tm_callback) {
60 assert(!ok);
61 return "without timeout callback";
62 }
63 ev->poll |= PE_T;
64 ev->tm.at = NVtime() + ev->timeout; /* too early okay */
65 pe_timeable_start(&ev->tm);
66 ++ok;
67 } else {
68 ev->poll &= ~PE_T;
69 }
70 return ok? 0 : "because there is nothing to watch";
71 }
72
pe_io_stop(pe_watcher * _ev)73 static void pe_io_stop(pe_watcher *_ev) {
74 pe_io *ev = (pe_io*) _ev;
75 pe_timeable_stop(&ev->tm);
76 if (!PE_RING_EMPTY(&ev->ioring)) {
77 pe_sys_io_del(ev);
78 PE_RING_DETACH(&ev->ioring);
79 --IOWatchCount;
80 IOWatch_OK = 0;
81 }
82 }
83
pe_io_alarm(pe_watcher * _wa,pe_timeable * hit)84 static void pe_io_alarm(pe_watcher *_wa, pe_timeable *hit) {
85 pe_io *wa = (pe_io*) _wa;
86 NV now = NVtime();
87 NV left = (_wa->cbtime + wa->timeout) - now;
88 if (left < IntervalEpsilon) {
89 pe_ioevent *ev;
90 if (WaREPEAT(wa)) {
91 wa->tm.at = now + wa->timeout;
92 pe_timeable_start(&wa->tm);
93 } else {
94 wa->timeout = 0; /*RESET*/
95 }
96 ev = (pe_ioevent*) (*_wa->vtbl->new_event)(_wa);
97 ++ev->base.hits;
98 ev->got |= PE_T;
99 if (wa->tm_callback) {
100 if (WaTMPERLCB(wa)) {
101 pe_anyevent_set_perl_cb(&ev->base, wa->tm_callback);
102 } else {
103 pe_anyevent_set_cb(&ev->base, wa->tm_callback, wa->tm_ext_data);
104 }
105 }
106 queueEvent((pe_event*) ev);
107 }
108 else {
109 /* ++TimeoutTooEarly;
110 This branch is normal behavior and does not indicate
111 poor clock accuracy. */
112 wa->tm.at = now + left;
113 pe_timeable_start(&wa->tm);
114 }
115 }
116
_io_restart(pe_watcher * ev)117 static void _io_restart(pe_watcher *ev) {
118 if (!WaPOLLING(ev)) return;
119 pe_watcher_off(ev);
120 pe_watcher_on(ev, 0);
121 }
122
pe_io_reset_handle(pe_watcher * ev)123 static void pe_io_reset_handle(pe_watcher *ev) { /* used by unix_io */
124 pe_io *io = (pe_io*)ev;
125 SvREFCNT_dec(io->handle);
126 io->handle = &PL_sv_undef;
127 io->fd = -1;
128 _io_restart(ev);
129 }
130
WKEYMETH(_io_poll)131 WKEYMETH(_io_poll) {
132 pe_io *io = (pe_io*)ev;
133 if (nval) {
134 int nev = sv_2events_mask(nval, PE_R|PE_W|PE_E|PE_T);
135 if (io->timeout) nev |= PE_T;
136 else nev &= ~PE_T;
137 if (io->poll != nev) {
138 io->poll = nev;
139 _io_restart(ev);
140 }
141 }
142 {
143 dSP;
144 XPUSHs(sv_2mortal(events_mask_2sv(io->poll)));
145 PUTBACK;
146 }
147 }
148
WKEYMETH(_io_handle)149 WKEYMETH(_io_handle) {
150 pe_io *io = (pe_io*)ev;
151 if (nval) {
152 SV *old = io->handle;
153 io->handle = SvREFCNT_inc(nval);
154 SvREFCNT_dec(old);
155 io->fd = -1;
156 _io_restart(ev);
157 }
158 {
159 dSP;
160 XPUSHs(io->handle);
161 PUTBACK;
162 }
163 }
164
WKEYMETH(_io_timeout)165 WKEYMETH(_io_timeout) {
166 pe_io *io = (pe_io*)ev;
167 if (nval) {
168 io->timeout = SvOK(nval)? SvNV(nval) : 0; /*undef is ok*/
169 _io_restart(ev);
170 }
171 {
172 dSP;
173 XPUSHs(sv_2mortal(newSVnv(io->timeout)));
174 PUTBACK;
175 }
176 }
177
WKEYMETH(_io_timeout_cb)178 WKEYMETH(_io_timeout_cb) {
179 pe_io *io = (pe_io*)ev;
180 if (nval) {
181 AV *av;
182 SV *sv;
183 SV *old=0;
184 if (WaTMPERLCB(ev))
185 old = (SV*) io->tm_callback;
186 if (!SvOK(nval)) {
187 WaTMPERLCB_off(ev);
188 io->tm_callback = 0;
189 io->tm_ext_data = 0;
190 } else if (SvROK(nval) && (SvTYPE(sv=SvRV(nval)) == SVt_PVCV)) {
191 WaTMPERLCB_on(ev);
192 io->tm_callback = SvREFCNT_inc(nval);
193 } else if (SvROK(nval) &&
194 (SvTYPE(av=(AV*)SvRV(nval)) == SVt_PVAV) &&
195 av_len(av) == 1 &&
196 !SvROK(sv=*av_fetch(av, 1, 0))) {
197 WaTMPERLCB_on(ev);
198 io->tm_callback = SvREFCNT_inc(nval);
199 } else {
200 if (SvIV(DebugLevel) >= 2)
201 sv_dump(sv);
202 croak("Callback must be a code ref or [$object, $method_name]");
203 }
204 if (old)
205 SvREFCNT_dec(old);
206 }
207 {
208 SV *ret = (WaTMPERLCB(ev)?
209 (SV*) io->tm_callback :
210 (io->tm_callback?
211 sv_2mortal(newSVpvf("<FPTR=0x%p EXT=0x%p>",
212 io->tm_callback, io->tm_ext_data)) :
213 &PL_sv_undef));
214 dSP;
215 XPUSHs(ret);
216 PUTBACK;
217 }
218 }
219
boot_io()220 static void boot_io() {
221 pe_watcher_vtbl *vt = &pe_io_vtbl;
222 memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
223 vt->dtor = pe_io_dtor;
224 vt->start = pe_io_start;
225 vt->stop = pe_io_stop;
226 vt->alarm = pe_io_alarm;
227 PE_RING_INIT(&IOWatch, 0);
228 IOWatch_OK = 0;
229 IOWatchCount = 0;
230 pe_register_vtbl(vt, gv_stashpv("Event::io",1), &ioevent_vtbl);
231 }
232