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