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