File Coverage

libev/ev_select.c
Criterion Covered Total %
statement 0 63 0.0
branch 0 36 0.0
condition n/a
subroutine n/a
pod n/a
total 0 99 0.0


line stmt bran cond sub pod time code
1             /*
2             * libev select fd activity backend
3             *
4             * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann
5             * All rights reserved.
6             *
7             * Redistribution and use in source and binary forms, with or without modifica-
8             * tion, are permitted provided that the following conditions are met:
9             *
10             * 1. Redistributions of source code must retain the above copyright notice,
11             * this list of conditions and the following disclaimer.
12             *
13             * 2. Redistributions in binary form must reproduce the above copyright
14             * notice, this list of conditions and the following disclaimer in the
15             * documentation and/or other materials provided with the distribution.
16             *
17             * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18             * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19             * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20             * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21             * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22             * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23             * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24             * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25             * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26             * OF THE POSSIBILITY OF SUCH DAMAGE.
27             *
28             * Alternatively, the contents of this file may be used under the terms of
29             * the GNU General Public License ("GPL") version 2 or any later version,
30             * in which case the provisions of the GPL are applicable instead of
31             * the above. If you wish to allow the use of your version of this file
32             * only under the terms of the GPL and not to allow others to use your
33             * version of this file under the BSD license, indicate your decision
34             * by deleting the provisions above and replace them with the notice
35             * and other provisions required by the GPL. If you do not delete the
36             * provisions above, a recipient may use your version of this file under
37             * either the BSD or the GPL.
38             */
39              
40             #ifndef _WIN32
41             /* for unix systems */
42             # include
43             # ifndef __hpux
44             /* for REAL unix systems */
45             # include
46             # endif
47             #endif
48              
49             #ifndef EV_SELECT_USE_FD_SET
50             # ifdef NFDBITS
51             # define EV_SELECT_USE_FD_SET 0
52             # else
53             # define EV_SELECT_USE_FD_SET 1
54             # endif
55             #endif
56              
57             #if EV_SELECT_IS_WINSOCKET
58             # undef EV_SELECT_USE_FD_SET
59             # define EV_SELECT_USE_FD_SET 1
60             # undef NFDBITS
61             # define NFDBITS 0
62             #endif
63              
64             #if !EV_SELECT_USE_FD_SET
65             # define NFDBYTES (NFDBITS / 8)
66             #endif
67              
68             #include
69              
70             static void
71 0           select_modify (EV_P_ int fd, int oev, int nev)
72             {
73 0 0         if (oev == nev)
74 0           return;
75              
76             {
77             #if EV_SELECT_USE_FD_SET
78              
79             #if EV_SELECT_IS_WINSOCKET
80             SOCKET handle = anfds [fd].handle;
81             #else
82             int handle = fd;
83             #endif
84              
85             assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
86              
87             /* FD_SET is broken on windows (it adds the fd to a set twice or more,
88             * which eventually leads to overflows). Need to call it only on changes.
89             */
90             #if EV_SELECT_IS_WINSOCKET
91             if ((oev ^ nev) & EV_READ)
92             #endif
93             if (nev & EV_READ)
94             FD_SET (handle, (fd_set *)vec_ri);
95             else
96             FD_CLR (handle, (fd_set *)vec_ri);
97              
98             #if EV_SELECT_IS_WINSOCKET
99             if ((oev ^ nev) & EV_WRITE)
100             #endif
101             if (nev & EV_WRITE)
102             FD_SET (handle, (fd_set *)vec_wi);
103             else
104             FD_CLR (handle, (fd_set *)vec_wi);
105              
106             #else
107              
108 0           int word = fd / NFDBITS;
109 0           fd_mask mask = 1UL << (fd % NFDBITS);
110              
111 0 0         if (ecb_expect_false (vec_max <= word))
112             {
113 0           int new_max = word + 1;
114              
115 0           vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
116 0           vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
117 0           vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
118 0           vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
119             #ifdef _WIN32
120             vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
121             #endif
122              
123 0 0         for (; vec_max < new_max; ++vec_max)
124 0           ((fd_mask *)vec_ri) [vec_max] =
125 0           ((fd_mask *)vec_wi) [vec_max] = 0;
126             }
127              
128 0           ((fd_mask *)vec_ri) [word] |= mask;
129 0 0         if (!(nev & EV_READ))
130 0           ((fd_mask *)vec_ri) [word] &= ~mask;
131              
132 0           ((fd_mask *)vec_wi) [word] |= mask;
133 0 0         if (!(nev & EV_WRITE))
134 0           ((fd_mask *)vec_wi) [word] &= ~mask;
135             #endif
136             }
137             }
138              
139             static void
140 0           select_poll (EV_P_ ev_tstamp timeout)
141             {
142             struct timeval tv;
143             int res;
144             int fd_setsize;
145              
146 0 0         EV_RELEASE_CB;
147 0           EV_TV_SET (tv, timeout);
148              
149             #if EV_SELECT_USE_FD_SET
150             fd_setsize = sizeof (fd_set);
151             #else
152 0           fd_setsize = vec_max * NFDBYTES;
153             #endif
154              
155 0           memcpy (vec_ro, vec_ri, fd_setsize);
156 0           memcpy (vec_wo, vec_wi, fd_setsize);
157              
158             #ifdef _WIN32
159             /* pass in the write set as except set.
160             * the idea behind this is to work around a windows bug that causes
161             * errors to be reported as an exception and not by setting
162             * the writable bit. this is so uncontrollably lame.
163             */
164             memcpy (vec_eo, vec_wi, fd_setsize);
165             res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);
166             #elif EV_SELECT_USE_FD_SET
167             fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;
168             res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
169             #else
170 0           res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
171             #endif
172 0 0         EV_ACQUIRE_CB;
173              
174 0 0         if (ecb_expect_false (res < 0))
175             {
176             #if EV_SELECT_IS_WINSOCKET
177             errno = WSAGetLastError ();
178             #endif
179             #ifdef WSABASEERR
180             /* on windows, select returns incompatible error codes, fix this */
181             if (errno >= WSABASEERR && errno < WSABASEERR + 1000)
182             if (errno == WSAENOTSOCK)
183             errno = EBADF;
184             else
185             errno -= WSABASEERR;
186             #endif
187              
188             #ifdef _WIN32
189             /* select on windows erroneously returns EINVAL when no fd sets have been
190             * provided (this is documented). what microsoft doesn't tell you that this bug
191             * exists even when the fd sets _are_ provided, so we have to check for this bug
192             * here and emulate by sleeping manually.
193             * we also get EINVAL when the timeout is invalid, but we ignore this case here
194             * and assume that EINVAL always means: you have to wait manually.
195             */
196             if (errno == EINVAL)
197             {
198             if (timeout)
199             {
200             unsigned long ms = EV_TS_TO_MSEC (timeout);
201             Sleep (ms ? ms : 1);
202             }
203              
204             return;
205             }
206             #endif
207              
208 0 0         if (errno == EBADF)
209 0           fd_ebadf (EV_A);
210 0 0         else if (errno == ENOMEM && !syserr_cb)
    0          
211 0           fd_enomem (EV_A);
212 0 0         else if (errno != EINTR)
213 0           ev_syserr ("(libev) select");
214              
215 0           return;
216             }
217              
218             #if EV_SELECT_USE_FD_SET
219              
220             {
221             int fd;
222              
223             for (fd = 0; fd < anfdmax; ++fd)
224             if (anfds [fd].events)
225             {
226             int events = 0;
227             #if EV_SELECT_IS_WINSOCKET
228             SOCKET handle = anfds [fd].handle;
229             #else
230             int handle = fd;
231             #endif
232              
233             if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
234             if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
235             #ifdef _WIN32
236             if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
237             #endif
238              
239             if (ecb_expect_true (events))
240             fd_event (EV_A_ fd, events);
241             }
242             }
243              
244             #else
245              
246             {
247             int word, bit;
248 0 0         for (word = vec_max; word--; )
249             {
250 0           fd_mask word_r = ((fd_mask *)vec_ro) [word];
251 0           fd_mask word_w = ((fd_mask *)vec_wo) [word];
252             #ifdef _WIN32
253             word_w |= ((fd_mask *)vec_eo) [word];
254             #endif
255              
256 0 0         if (word_r || word_w)
    0          
257 0 0         for (bit = NFDBITS; bit--; )
258             {
259 0           fd_mask mask = 1UL << bit;
260 0           int events = 0;
261              
262 0           events |= word_r & mask ? EV_READ : 0;
263 0 0         events |= word_w & mask ? EV_WRITE : 0;
264              
265 0 0         if (ecb_expect_true (events))
266 0           fd_event (EV_A_ word * NFDBITS + bit, events);
267             }
268             }
269             }
270              
271             #endif
272             }
273              
274             inline_size
275             int
276 0           select_init (EV_P_ int flags)
277             {
278 0           backend_mintime = EV_TS_CONST (1e-6);
279 0           backend_modify = select_modify;
280 0           backend_poll = select_poll;
281              
282             #if EV_SELECT_USE_FD_SET
283             vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);
284             vec_ro = ev_malloc (sizeof (fd_set));
285             vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);
286             vec_wo = ev_malloc (sizeof (fd_set));
287             #ifdef _WIN32
288             vec_eo = ev_malloc (sizeof (fd_set));
289             #endif
290             #else
291 0           vec_max = 0;
292 0           vec_ri = 0;
293 0           vec_ro = 0;
294 0           vec_wi = 0;
295 0           vec_wo = 0;
296             #ifdef _WIN32
297             vec_eo = 0;
298             #endif
299             #endif
300              
301 0           return EVBACKEND_SELECT;
302             }
303              
304             inline_size
305             void
306 0           select_destroy (EV_P)
307             {
308 0           ev_free (vec_ri);
309 0           ev_free (vec_ro);
310 0           ev_free (vec_wi);
311 0           ev_free (vec_wo);
312             #ifdef _WIN32
313             ev_free (vec_eo);
314             #endif
315 0           }
316