xref: /freebsd/crypto/krb5/src/util/verto/ev_select.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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