]> granicus.if.org Git - curl/commitdiff
New Internal wrapper function Curl_select() around select (2), it
authorYang Tse <yangsita@gmail.com>
Tue, 27 Mar 2007 18:15:26 +0000 (18:15 +0000)
committerYang Tse <yangsita@gmail.com>
Tue, 27 Mar 2007 18:15:26 +0000 (18:15 +0000)
uses poll() when a fine poll() is available, so now libcurl can be
built without select() support at all if a fine poll() is available.

CHANGES
RELEASE-NOTES
lib/easy.c
lib/hostares.c
lib/select.c
lib/select.h

diff --git a/CHANGES b/CHANGES
index 0e3d52d1e3216f680fed0c1c724a8ea162cb3a9a..d4d9f5837406dfd15d612625051e4e5e77ba8b4a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,10 @@
 Yang Tse (27 March 2007)
 - Internal function Curl_select() renamed to Curl_socket_ready()
 
+  New Internal wrapper function Curl_select() around select (2), it
+  uses poll() when a fine poll() is available, so now libcurl can be
+  built without select() support at all if a fine poll() is available.
+
 Daniel S (25 March 2007)
 - Daniel Johnson fixed multi code to traverse the easy handle list properly.
   A left-over bug from the February 21 fix.
index 759e49b181fdfec2697446c130e22ec2131316f7..0661b8d989dea164abf8155287c073f4c9d0edbe 100644 (file)
@@ -24,6 +24,7 @@ This release includes the following changes:
  o added experimental CURL_ACKNOWLEDGE_EINTR symbol definition check
  o --key and new --pubkey options for SSH public key file logins
  o --pass now works for a SSH public key file, too
+ o select (2) support no longer needed to build the library if poll() used
 
 This release includes the following bugfixes:
 
index c16654d65f4092915ca58ddb0142a6d09423f824..dc18c7488153dd4694eb7be37073f4291896b776 100644 (file)
 #include <sys/param.h>
 #endif
 
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
 #endif  /* WIN32 ... */
 
 #include "urldata.h"
@@ -79,6 +75,7 @@
 #include "memory.h"
 #include "progress.h"
 #include "easyif.h"
+#include "select.h"
 #include "sendf.h" /* for failf function prototype */
 #include <ca-bundle.h>
 
@@ -417,7 +414,7 @@ CURLcode curl_easy_perform(CURL *easy)
     /* get file descriptors from the transfers */
     curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
 
-    rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+    rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
 
     if(rc == -1)
       /* select error */
index c9fbcc6de2abdaca8867b092dcdae5a881eeca21..dae1ca3b74a352930d4e310477c91dd3286a596e 100644 (file)
@@ -74,6 +74,7 @@
 #include "url.h"
 #include "multiif.h"
 #include "connect.h"
+#include "select.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -144,8 +145,8 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
 
   nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
 
-  (void)select(nfds, &read_fds, &write_fds, NULL,
-               (struct timeval *)&tv);
+  (void)Curl_select(nfds, &read_fds, &write_fds, NULL,
+                    (struct timeval *)&tv);
 
   /* Call ares_process() unconditonally here, even if we simply timed out
      above, as otherwise the ares name resolve won't timeout! */
@@ -210,7 +211,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
       /* no file descriptors means we're done waiting */
       break;
     tvp = ares_timeout(data->state.areschannel, &store, &tv);
-    count = select(nfds, &read_fds, &write_fds, NULL, tvp);
+    count = Curl_select(nfds, &read_fds, &write_fds, NULL, tvp);
     if ((count < 0) && (SOCKERRNO != EINVAL))
       break;
 
index 161a62161679941aaa988d0eb5d10632f6e30fd3..2e25adede82c6f331bb6d1155dab94a098d99bb7 100644 (file)
@@ -32,8 +32,8 @@
 #include <sys/time.h>
 #endif
 
-#ifndef HAVE_SELECT
-#error "We can't compile without select() support!"
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
+#error "We can't compile without select() or poll() support."
 #endif
 
 #ifdef __BEOS__
@@ -64,6 +64,7 @@
 
 #if defined(USE_WINSOCK) || defined(TPF)
 #define VERIFY_SOCK(x) do { } while (0)
+#define VERIFY_NFDS(x) do { } while (0)
 #else
 #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
 #define VERIFY_SOCK(x) do { \
     return -1; \
   } \
 } while(0)
+#define VALID_NFDS(n) (((n) >= 0) && ((n) <= FD_SETSIZE))
+#define VERIFY_NFDS(x) do { \
+  if(!VALID_NFDS(x)) { \
+    SET_SOCKERRNO(EINVAL); \
+    return -1; \
+  } \
+} while(0)
 #endif
 
 /* Convenience local macros */
@@ -84,6 +92,8 @@
 #define error_not_EINTR  (1)
 #endif
 
+#define SMALL_POLLNFDS  0X20
+
 /*
  * Internal function used for waiting a specific amount of ms
  * in Curl_socket_ready() and Curl_poll() when no file descriptor
@@ -424,6 +434,189 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
   return r;
 }
 
+/*
+ * This is a wrapper around select().  It uses poll() when a fine
+ * poll() is available, in order to avoid limits with FD_SETSIZE,
+ * otherwise select() is used.  An error is returned if select() is
+ * being used and a the number of file descriptors is larger than
+ * FD_SETSIZE.  A NULL timeout pointer makes this function wait
+ * indefinitely, unles no valid file descriptor is given, when this
+ * happens the NULL timeout is ignored and the function times out
+ * immediately.  When compiled with CURL_ACKNOWLEDGE_EINTR defined,
+ * EINTR condition is honored and function might exit early without
+ * awaiting timeout, otherwise EINTR will be ignored.
+ *
+ * Return values:
+ *   -1 = system call error or nfds > FD_SETSIZE
+ *    0 = timeout
+ *    N = number of file descriptors kept in file descriptor sets.
+ */
+int Curl_select(int nfds,
+                fd_set *fds_read, fd_set *fds_write, fd_set *fds_excep,
+                struct timeval *timeout)
+{
+  struct timeval initial_tv;
+  int timeout_ms;
+  int pending_ms;
+  int error;
+  int r;
+#ifdef HAVE_POLL_FINE
+  struct pollfd small_fds[SMALL_POLLNFDS];
+  struct pollfd *poll_fds;
+  int ix;
+  int fd;
+  int poll_nfds = 0;
+#else
+  struct timeval pending_tv;
+  struct timeval *ptimeout;
+#endif
+  int ret = 0;
+
+  if ((nfds < 0) ||
+     ((nfds > 0) && (!fds_read && !fds_write && !fds_excep))) {
+    SET_SOCKERRNO(EINVAL);
+    return -1;
+  }
+
+  if (timeout) {
+    if ((timeout->tv_sec < 0) ||
+        (timeout->tv_usec < 0) ||
+        (timeout->tv_usec >= 1000000)) {
+      SET_SOCKERRNO(EINVAL);
+      return -1;
+    }
+    timeout_ms = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
+  }
+  else {
+    timeout_ms = -1;
+  }
+
+  if ((!nfds) || (!fds_read && !fds_write && !fds_excep)) {
+    r = wait_ms(timeout_ms);
+    return r;
+  }
+
+  pending_ms = timeout_ms;
+  initial_tv = curlx_tvnow();
+
+#ifdef HAVE_POLL_FINE
+
+  if (fds_read || fds_write || fds_excep) {
+    fd = nfds;
+    while (fd--) {
+      if ((fds_read && (0 != FD_ISSET(fd, fds_read))) ||
+          (fds_write && (0 != FD_ISSET(fd, fds_write))) ||
+          (fds_excep && (0 != FD_ISSET(fd, fds_excep))))
+        poll_nfds++;
+    }
+  }
+
+  if (!poll_nfds)
+    poll_fds = NULL;
+  else if (poll_nfds <= SMALL_POLLNFDS)
+    poll_fds = small_fds;
+  else {
+    poll_fds = calloc((size_t)poll_nfds, sizeof(struct pollfd));
+    if (!poll_fds) {
+      SET_SOCKERRNO(ENOBUFS);
+      return -1;
+    }
+  }
+
+  if (poll_fds) {
+    ix = 0;
+    fd = nfds;
+    while (fd--) {
+      poll_fds[ix].events = 0;
+      if (fds_read && (0 != FD_ISSET(fd, fds_read)))
+        poll_fds[ix].events |= (POLLRDNORM|POLLIN);
+      if (fds_write && (0 != FD_ISSET(fd, fds_write)))
+        poll_fds[ix].events |= (POLLWRNORM|POLLOUT);
+      if (fds_excep && (0 != FD_ISSET(fd, fds_excep)))
+        poll_fds[ix].events |= (POLLRDBAND|POLLPRI);
+      if (poll_fds[ix].events) {
+        poll_fds[ix].fd = fd;
+        poll_fds[ix].revents = 0;
+        ix++;
+      }
+    }
+  }
+
+  do {
+    if (timeout_ms < 0)
+      pending_ms = -1;
+    r = poll(poll_fds, poll_nfds, pending_ms);
+  } while ((r == -1) && (error = SOCKERRNO) &&
+           (error != EINVAL) && error_not_EINTR &&
+           ((timeout_ms < 0) || ((pending_ms = timeout_ms - elapsed_ms) > 0)));
+
+  if (r < 0)
+    ret = -1;
+
+  if (r > 0) {
+    ix = poll_nfds;
+    while (ix--) {
+      if (poll_fds[ix].revents & POLLNVAL) {
+        SET_SOCKERRNO(EBADF);
+        ret = -1;
+        break;
+      }
+    }
+  }
+
+  if (!ret) {
+    ix = poll_nfds;
+    while (ix--) {
+      if (fds_read && (0 != FD_ISSET(poll_fds[ix].fd, fds_read))) {
+        if (0 == (poll_fds[ix].revents & (POLLRDNORM|POLLERR|POLLHUP|POLLIN)))
+          FD_CLR(poll_fds[ix].fd, fds_read);
+        else
+          ret++;
+      }
+      if (fds_write && (0 != FD_ISSET(poll_fds[ix].fd, fds_write))) {
+        if (0 == (poll_fds[ix].revents & (POLLWRNORM|POLLERR|POLLHUP|POLLOUT)))
+          FD_CLR(poll_fds[ix].fd, fds_write);
+        else
+          ret++;
+      }
+      if (fds_excep && (0 != FD_ISSET(poll_fds[ix].fd, fds_excep))) {
+        if (0 == (poll_fds[ix].revents & (POLLRDBAND|POLLERR|POLLHUP|POLLPRI)))
+          FD_CLR(poll_fds[ix].fd, fds_excep);
+        else
+          ret++;
+      }
+    }
+  }
+
+  if (poll_fds && (poll_nfds > SMALL_POLLNFDS))
+    free(poll_fds);
+
+#else  /* HAVE_POLL_FINE */
+
+  VERIFY_NFDS(nfds);
+
+  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+  do {
+    if (ptimeout) {
+      pending_tv.tv_sec = pending_ms / 1000;
+      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+    }
+    r = select(nfds, fds_read, fds_write, fds_excep, ptimeout);
+  } while ((r == -1) && (error = SOCKERRNO) &&
+           (error != EINVAL) && (error != EBADF) && error_not_EINTR &&
+           ((timeout_ms < 0) || ((pending_ms = timeout_ms - elapsed_ms) > 0)));
+
+  if (r < 0)
+    ret = -1;
+  else
+    ret = r;
+
+#endif  /* HAVE_POLL_FINE */
+
+  return ret;
+}
+
 #ifdef TPF
 /*
  * This is a replacement for select() on the TPF platform.
index 8c59f155e6ee4040d9344424fac2a77890062ee3..5a62a6fd8981043abf8f0dbf7ec3d9887466d71b 100644 (file)
@@ -64,6 +64,18 @@ struct pollfd
 
 #endif
 
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+#ifndef POLLRDBAND
+#define POLLRDBAND POLLPRI
+#endif
+
 #define CSELECT_IN   0x01
 #define CSELECT_OUT  0x02
 #define CSELECT_ERR  0x04
@@ -72,6 +84,10 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int timeout_m
 
 int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
 
+int Curl_select(int nfds,
+                fd_set *fds_read, fd_set *fds_write, fd_set *fds_excep,
+                struct timeval *timeout);
+
 #ifdef TPF
 int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
                        fd_set* excepts, struct timeval* tv);