File Coverage

c/io.c
Criterion Covered Total %
statement 157 165 95.1
branch 63 98 64.2
condition n/a
subroutine n/a
pod n/a
total 220 263 83.6


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