--- libev/ev_select.c 2008/05/26 04:14:32 1.33 +++ libev/ev_select.c 2009/01/07 17:54:57 1.41 @@ -1,7 +1,7 @@ /* * libev select fd activity backend * - * Copyright (c) 2007,2008 Marc Alexander Lehmann + * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -54,6 +54,8 @@ #if EV_SELECT_IS_WINSOCKET # undef EV_SELECT_USE_FD_SET # define EV_SELECT_USE_FD_SET 1 +# undef NFDBITS +# define NFDBITS 0 #endif #if !EV_SELECT_USE_FD_SET @@ -70,22 +72,32 @@ { #if EV_SELECT_USE_FD_SET - #if EV_SELECT_IS_WINSOCKET SOCKET handle = anfds [fd].handle; #else int handle = fd; #endif - if (nev & EV_READ) - FD_SET (handle, (fd_set *)vec_ri); - else - FD_CLR (handle, (fd_set *)vec_ri); - - if (nev & EV_WRITE) - FD_SET (handle, (fd_set *)vec_wi); - else - FD_CLR (handle, (fd_set *)vec_wi); + assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE)); + + /* FD_SET is broken on windows (it adds the fd to a set twice or more, + * which eventually leads to overflows). Need to call it only on changes. + */ + #if EV_SELECT_IS_WINSOCKET + if ((oev ^ nev) & EV_READ) + #endif + if (nev & EV_READ) + FD_SET (handle, (fd_set *)vec_ri); + else + FD_CLR (handle, (fd_set *)vec_ri); + + #if EV_SELECT_IS_WINSOCKET + if ((oev ^ nev) & EV_WRITE) + #endif + if (nev & EV_WRITE) + FD_SET (handle, (fd_set *)vec_wi); + else + FD_CLR (handle, (fd_set *)vec_wi); #else @@ -147,6 +159,9 @@ */ memcpy (vec_eo, vec_wi, fd_setsize); res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv); +#elif EV_SELECT_USE_FD_SET + fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE; + res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); #else res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv); #endif @@ -168,7 +183,7 @@ #ifdef _WIN32 /* select on windows errornously returns EINVAL when no fd sets have been * provided (this is documented). what microsoft doesn't tell you that this bug - * exists even when the fd sets are provided, so we have to check for this bug + * exists even when the fd sets _are_ provided, so we have to check for this bug * here and emulate by sleeping manually. * we also get EINVAL when the timeout is invalid, but we ignore this case here * and assume that EINVAL always means: you have to wait manually. @@ -185,7 +200,7 @@ else if (errno == ENOMEM && !syserr_cb) fd_enomem (EV_A); else if (errno != EINTR) - syserr ("(libev) select"); + ev_syserr ("(libev) select"); return; } @@ -254,7 +269,6 @@ backend_poll = select_poll; #if EV_SELECT_USE_FD_SET - vec_max = FD_SETSIZE / 32; vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri); vec_ro = ev_malloc (sizeof (fd_set)); vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);