summaryrefslogtreecommitdiff
path: root/lib/select.c
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2007-03-20 20:00:40 +0000
committerYang Tse <yangsita@gmail.com>2007-03-20 20:00:40 +0000
commite4b754f64ed02ce85f6deb13908c833cd3b32231 (patch)
tree35bee2a0b564f8906f688dd54697b66a4ab84056 /lib/select.c
parent34ed4642ecec17ec3f3bf6bba304a07b141458cd (diff)
downloadcurl-e4b754f64ed02ce85f6deb13908c833cd3b32231.tar.gz
Fixed: When a signal was caught awaiting for an event using Curl_select()
or Curl_poll() with a non-zero timeout both functions would restart the specified timeout. This could even lead to the extreme case that if a signal arrived with a frecuency lower to the specified timeout neither function would ever exit. Added experimental symbol definition check CURL_ACKNOWLEDGE_EINTR in Curl_select() and Curl_poll(). When compiled with CURL_ACKNOWLEDGE_EINTR defined both functions will return as soon as a signal is caught. Use it at your own risk, all calls to these functions in the library should be revisited and checked before fully supporting this feature.
Diffstat (limited to 'lib/select.c')
-rw-r--r--lib/select.c126
1 files changed, 94 insertions, 32 deletions
diff --git a/lib/select.c b/lib/select.c
index 32261f2c0..1b0e8643a 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -51,6 +51,13 @@
#include "connect.h"
#include "select.h"
+#ifdef USE_WINSOCK
+# undef EINTR
+# define EINTR WSAEINTR
+# undef EINVAL
+# define EINVAL WSAEINVAL
+#endif
+
/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */
#if defined(USE_WINSOCK) || defined(TPF)
@@ -98,11 +105,19 @@ static void wait_ms(int timeout_ms)
/*
* This is an internal function used for waiting for read or write
- * events on single file descriptors. It attempts to replace select()
- * in order to avoid limits with FD_SETSIZE.
+ * events on a pair of file descriptors. 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 file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
+ * is honored and function will exit early without awaiting timeout,
+ * otherwise EINTR will be ignored.
*
* Return values:
- * -1 = system call error
+ * -1 = system call error or fd >= FD_SETSIZE
* 0 = timeout
* CSELECT_IN | CSELECT_OUT | CSELECT_ERR
*/
@@ -112,12 +127,15 @@ int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
struct pollfd pfd[2];
int num;
#else
- struct timeval timeout;
+ struct timeval pending_tv;
+ struct timeval *ptimeout;
fd_set fds_read;
fd_set fds_write;
fd_set fds_err;
curl_socket_t maxfd;
#endif
+ struct timeval initial_tv;
+ int pending_ms;
int r;
int ret;
@@ -126,23 +144,35 @@ int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
return 0;
}
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+
#ifdef HAVE_POLL_FINE
num = 0;
if (readfd != CURL_SOCKET_BAD) {
pfd[num].fd = readfd;
pfd[num].events = POLLIN;
+ pfd[num].revents = 0;
num++;
}
if (writefd != CURL_SOCKET_BAD) {
pfd[num].fd = writefd;
pfd[num].events = POLLOUT;
+ pfd[num].revents = 0;
num++;
}
do {
- r = poll(pfd, num, timeout_ms);
- } while((r == -1) && (SOCKERRNO == EINTR));
+ if (timeout_ms < 0)
+ pending_ms = -1;
+ r = poll(pfd, num, pending_ms);
+ } while ((r == -1) && (SOCKERRNO != EINVAL) &&
+#ifdef CURL_ACKNOWLEDGE_EINTR
+ (SOCKERRNO != EINTR) &&
+#endif
+ ((timeout_ms < 0) ||
+ ((pending_ms = timeout_ms - curlx_tvdiff(curlx_tvnow(), initial_tv)) > 0)));
if (r < 0)
return -1;
@@ -176,9 +206,6 @@ int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
#else /* HAVE_POLL_FINE */
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
-
FD_ZERO(&fds_err);
maxfd = (curl_socket_t)-1;
@@ -199,9 +226,20 @@ int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
maxfd = writefd;
}
+ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
do {
- r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
- } while((r == -1) && (SOCKERRNO == EINTR));
+ if (ptimeout) {
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ }
+ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+ } while ((r == -1) && (SOCKERRNO != EINVAL) &&
+#ifdef CURL_ACKNOWLEDGE_EINTR
+ (SOCKERRNO != EINTR) &&
+#endif
+ ((timeout_ms < 0) ||
+ ((pending_ms = timeout_ms - curlx_tvdiff(curlx_tvnow(), initial_tv)) > 0)));
if (r < 0)
return -1;
@@ -231,25 +269,33 @@ int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
/*
* This is a wrapper around poll(). If poll() does not exist, then
* select() is used instead. An error is returned if select() is
- * being used and a file descriptor too large for FD_SETSIZE.
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
+ * is honored and function will exit early without awaiting timeout,
+ * otherwise EINTR will be ignored.
*
* Return values:
* -1 = system call error or fd >= FD_SETSIZE
* 0 = timeout
- * 1 = number of structures with non zero revent fields
+ * N = number of structures with non zero revent fields
*/
int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
{
#ifndef HAVE_POLL_FINE
- struct timeval timeout;
+ struct timeval pending_tv;
struct timeval *ptimeout;
fd_set fds_read;
fd_set fds_write;
fd_set fds_err;
curl_socket_t maxfd;
#endif
+ struct timeval initial_tv;
bool fds_none = TRUE;
unsigned int i;
+ int pending_ms;
int r;
if (ufds) {
@@ -265,11 +311,21 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
return 0;
}
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+
#ifdef HAVE_POLL_FINE
do {
- r = poll(ufds, nfds, timeout_ms);
- } while((r == -1) && (SOCKERRNO == EINTR));
+ if (timeout_ms < 0)
+ pending_ms = -1;
+ r = poll(ufds, nfds, pending_ms);
+ } while ((r == -1) && (SOCKERRNO != EINVAL) &&
+#ifdef CURL_ACKNOWLEDGE_EINTR
+ (SOCKERRNO != EINTR) &&
+#endif
+ ((timeout_ms < 0) ||
+ ((pending_ms = timeout_ms - curlx_tvdiff(curlx_tvnow(), initial_tv)) > 0)));
#else /* HAVE_POLL_FINE */
@@ -279,30 +335,36 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
maxfd = (curl_socket_t)-1;
for (i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
if (ufds[i].fd == CURL_SOCKET_BAD)
continue;
VERIFY_SOCK(ufds[i].fd);
- if (ufds[i].fd > maxfd)
- maxfd = ufds[i].fd;
- if (ufds[i].events & POLLIN)
- FD_SET(ufds[i].fd, &fds_read);
- if (ufds[i].events & POLLOUT)
- FD_SET(ufds[i].fd, &fds_write);
- if (ufds[i].events & POLLERR)
- FD_SET(ufds[i].fd, &fds_err);
+ if (ufds[i].events & (POLLIN|POLLOUT|POLLERR)) {
+ if (ufds[i].fd > maxfd)
+ maxfd = ufds[i].fd;
+ if (ufds[i].events & POLLIN)
+ FD_SET(ufds[i].fd, &fds_read);
+ if (ufds[i].events & POLLOUT)
+ FD_SET(ufds[i].fd, &fds_write);
+ if (ufds[i].events & POLLERR)
+ FD_SET(ufds[i].fd, &fds_err);
+ }
}
- if (timeout_ms < 0) {
- ptimeout = NULL; /* wait forever */
- } else {
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
- ptimeout = &timeout;
- }
+ 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((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
- } while((r == -1) && (SOCKERRNO == EINTR));
+ } while ((r == -1) && (SOCKERRNO != EINVAL) &&
+#ifdef CURL_ACKNOWLEDGE_EINTR
+ (SOCKERRNO != EINTR) &&
+#endif
+ ((timeout_ms < 0) ||
+ ((pending_ms = timeout_ms - curlx_tvdiff(curlx_tvnow(), initial_tv)) > 0)));
if (r < 0)
return -1;