1 /* 2 * libev select fd activity backend 3 * 4 * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de> 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 <inttypes.h> 43 # ifndef __hpux 44 /* for REAL unix systems */ 45 # include <sys/select.h> 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 <string.h> 69 70 static void 71 select_modify (EV_P_ int fd, int oev, int nev) 72 { 73 if (oev == nev) 74 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 int word = fd / NFDBITS; 109 fd_mask mask = 1UL << (fd % NFDBITS); 110 111 if (expect_false (vec_max <= word)) 112 { 113 int new_max = word + 1; 114 115 vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES); 116 vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */ 117 vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES); 118 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 for (; vec_max < new_max; ++vec_max) 124 ((fd_mask *)vec_ri) [vec_max] = 125 ((fd_mask *)vec_wi) [vec_max] = 0; 126 } 127 128 ((fd_mask *)vec_ri) [word] |= mask; 129 if (!(nev & EV_READ)) 130 ((fd_mask *)vec_ri) [word] &= ~mask; 131 132 ((fd_mask *)vec_wi) [word] |= mask; 133 if (!(nev & EV_WRITE)) 134 ((fd_mask *)vec_wi) [word] &= ~mask; 135 #endif 136 } 137 } 138 139 static void 140 select_poll (EV_P_ ev_tstamp timeout) 141 { 142 struct timeval tv; 143 int res; 144 int fd_setsize; 145 146 EV_RELEASE_CB; 147 EV_TV_SET (tv, timeout); 148 149 #if EV_SELECT_USE_FD_SET 150 fd_setsize = sizeof (fd_set); 151 #else 152 fd_setsize = vec_max * NFDBYTES; 153 #endif 154 155 memcpy (vec_ro, vec_ri, fd_setsize); 156 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 res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); 171 #endif 172 EV_ACQUIRE_CB; 173 174 if (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 = timeout * 1e3; 201 Sleep (ms ? ms : 1); 202 } 203 204 return; 205 } 206 #endif 207 208 if (errno == EBADF) 209 fd_ebadf (EV_A); 210 else if (errno == ENOMEM && !syserr_cb) 211 fd_enomem (EV_A); 212 else if (errno != EINTR) 213 ev_syserr ("(libev) select"); 214 215 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 (expect_true (events)) 240 fd_event (EV_A_ fd, events); 241 } 242 } 243 244 #else 245 246 { 247 int word, bit; 248 for (word = vec_max; word--; ) 249 { 250 fd_mask word_r = ((fd_mask *)vec_ro) [word]; 251 fd_mask word_w = ((fd_mask *)vec_wo) [word]; 252 #ifdef _WIN32 253 word_w |= ((fd_mask *)vec_eo) [word]; 254 #endif 255 256 if (word_r || word_w) 257 for (bit = NFDBITS; bit--; ) 258 { 259 fd_mask mask = 1UL << bit; 260 int events = 0; 261 262 events |= word_r & mask ? EV_READ : 0; 263 events |= word_w & mask ? EV_WRITE : 0; 264 265 if (expect_true (events)) 266 fd_event (EV_A_ word * NFDBITS + bit, events); 267 } 268 } 269 } 270 271 #endif 272 } 273 274 int inline_size 275 select_init (EV_P_ int flags) 276 { 277 backend_mintime = 1e-6; 278 backend_modify = select_modify; 279 backend_poll = select_poll; 280 281 #if EV_SELECT_USE_FD_SET 282 vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); 283 vec_ro = ev_malloc (sizeof (fd_set)); 284 vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi); 285 vec_wo = ev_malloc (sizeof (fd_set)); 286 #ifdef _WIN32 287 vec_eo = ev_malloc (sizeof (fd_set)); 288 #endif 289 #else 290 vec_max = 0; 291 vec_ri = 0; 292 vec_ro = 0; 293 vec_wi = 0; 294 vec_wo = 0; 295 #ifdef _WIN32 296 vec_eo = 0; 297 #endif 298 #endif 299 300 return EVBACKEND_SELECT; 301 } 302 303 void inline_size 304 select_destroy (EV_P) 305 { 306 ev_free (vec_ri); 307 ev_free (vec_ro); 308 ev_free (vec_wi); 309 ev_free (vec_wo); 310 #ifdef _WIN32 311 ev_free (vec_eo); 312 #endif 313 } 314 315