ext/libev/ev_select.c in rev-0.2.2 vs ext/libev/ev_select.c in rev-0.2.3
- old
+ new
@@ -1,9 +1,9 @@
/*
* libev select fd activity backend
*
- * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
@@ -52,10 +52,12 @@
#endif
#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
# define NFDBYTES (NFDBITS / 8)
#endif
@@ -75,20 +77,31 @@
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);
+ assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
- if (nev & EV_WRITE)
- FD_SET (handle, (fd_set *)vec_wi);
- else
- FD_CLR (handle, (fd_set *)vec_wi);
+ /* 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
int word = fd / NFDBITS;
fd_mask mask = 1UL << (fd % NFDBITS);
@@ -98,10 +111,13 @@
vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
+ #ifdef _WIN32
+ vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
+ #endif
for (; vec_max < new_max; ++vec_max)
((fd_mask *)vec_ri) [vec_max] =
((fd_mask *)vec_wi) [vec_max] = 0;
}
@@ -120,23 +136,38 @@
static void
select_poll (EV_P_ ev_tstamp timeout)
{
struct timeval tv;
int res;
+ int fd_setsize;
+ tv.tv_sec = (long)timeout;
+ tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6);
+
#if EV_SELECT_USE_FD_SET
- memcpy (vec_ro, vec_ri, sizeof (fd_set));
- memcpy (vec_wo, vec_wi, sizeof (fd_set));
+ fd_setsize = sizeof (fd_set);
#else
- memcpy (vec_ro, vec_ri, vec_max * NFDBYTES);
- memcpy (vec_wo, vec_wi, vec_max * NFDBYTES);
+ fd_setsize = vec_max * NFDBYTES;
#endif
- tv.tv_sec = (long)timeout;
- tv.tv_usec = (long)((timeout - (ev_tstamp)tv.tv_sec) * 1e6);
+ memcpy (vec_ro, vec_ri, fd_setsize);
+ memcpy (vec_wo, vec_wi, fd_setsize);
+#ifdef _WIN32
+ /* pass in the write set as except set.
+ * the idea behind this is to work around a windows bug that causes
+ * errors to be reported as an exception and not by setting
+ * the writable bit. this is so uncontrollably lame.
+ */
+ 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
if (expect_false (res < 0))
{
#if EV_SELECT_IS_WINSOCKET
errno = WSAGetLastError ();
@@ -151,11 +182,11 @@
#endif
#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.
*/
if (errno == EINVAL)
@@ -168,11 +199,11 @@
if (errno == EBADF)
fd_ebadf (EV_A);
else if (errno == ENOMEM && !syserr_cb)
fd_enomem (EV_A);
else if (errno != EINTR)
- syserr ("(libev) select");
+ ev_syserr ("(libev) select");
return;
}
#if EV_SELECT_USE_FD_SET
@@ -190,10 +221,13 @@
int handle = fd;
#endif
if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
+ #ifdef _WIN32
+ if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
+ #endif
if (expect_true (events))
fd_event (EV_A_ fd, events);
}
}
@@ -204,10 +238,13 @@
int word, bit;
for (word = vec_max; word--; )
{
fd_mask word_r = ((fd_mask *)vec_ro) [word];
fd_mask word_w = ((fd_mask *)vec_wo) [word];
+ #ifdef _WIN32
+ word_w |= ((fd_mask *)vec_eo) [word];
+ #endif
if (word_r || word_w)
for (bit = NFDBITS; bit--; )
{
fd_mask mask = 1UL << bit;
@@ -231,14 +268,16 @@
backend_fudge = 0.; /* posix says this is zero */
backend_modify = select_modify;
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);
vec_wo = ev_malloc (sizeof (fd_set));
+ #ifdef _WIN32
+ vec_eo = ev_malloc (sizeof (fd_set));
+ #endif
#else
vec_max = 0;
vec_ri = 0;
vec_ri = 0;
vec_wo = 0;