Commit eed47311 authored by Yang Tse's avatar Yang Tse
Browse files

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.
parent 59eaae42
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -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:

+2 −5
Original line number Diff line number Diff line
@@ -61,10 +61,6 @@
#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 */
+4 −3
Original line number Diff line number Diff line
@@ -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,7 +145,7 @@ 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,
  (void)Curl_select(nfds, &read_fds, &write_fds, NULL,
                    (struct timeval *)&tv);

  /* Call ares_process() unconditonally here, even if we simply timed out
@@ -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;

+195 −2
Original line number Diff line number Diff line
@@ -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 { \
@@ -72,6 +73,13 @@
    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.
Loading