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