diff options
author | Daniel Stenberg <daniel@haxx.se> | 2007-03-11 09:11:29 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2007-03-11 09:11:29 +0000 |
commit | c8cd13337efcd45e918fab824b226e4ae6338ea0 (patch) | |
tree | 41c1184f8a80120d392ae8a94e272eb045e4a22e /lib/select.c | |
parent | 40e9e40cb41f3755b7a07c7d73cac59a6633f121 (diff) |
reverted the pselect patch => http://curl.haxx.se/mail/lib-2007-03/0100.html
Diffstat (limited to 'lib/select.c')
-rw-r--r-- | lib/select.c | 169 |
1 files changed, 19 insertions, 150 deletions
diff --git a/lib/select.c b/lib/select.c index a1e149a12..4f8878401 100644 --- a/lib/select.c +++ b/lib/select.c @@ -32,7 +32,9 @@ #include <sys/time.h> #endif -#include <signal.h> +#ifndef HAVE_SELECT +#error "We can't compile without select() support!" +#endif #ifdef __BEOS__ /* BeOS has FD_SET defined in socket.h */ @@ -51,57 +53,6 @@ /* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */ -/* There are various ways to wait for a socket to be ready to give or take - * data. None of them are perfect. - * - * select() is available everywhere, but cannot take a file - * descriptor numerically greater than FD_SETSIZE but cannot be reliably - * interrupted by a signal. - * - * pselect() works with signals, but still has the file descriptor problem. - * And some older systems don't have it. - * - * poll() (and equivalently on Windows, WSAPoll()) can take any file - * descriptor, but has the signal problem. And some older systems - * don't have it. - * - * The signal issue is this: We would like to be able to avoid the - * wait if a signal has arrived since we last checked for it. All - * these methods terminate the wait (with EINTR) if a signal arrives - * while the waiting is underway, so it's just signals that happen - * shortly before the wait that are a problem. With pselect(), this - * is possible because it has the ability to simultaneously unblock - * signals _after_ the wait begins. So you just block signals, then - * check for arrival, then assuming no signals have arrived, call - * pselect() with an argument that says to unblock signals. Any - * signal that arrived after you blocked will thus interrupt the wait - * and pselect() returns immediately. - * - * Curl_pselect() is our compromise among these. We use poll() - * whenever it is available and select() otherwise. We emulate - * pselect-like signal behavior by unblocking signals just before - * calling poll() or select() and re-blocking after. This only - * _approximates_ pselect(), because there is a window in which a - * signal may arrive and we wait anyway. - * - * To reduce that window, we use pselect(), if it is available -- - * with no file descriptors -- just before the poll() or select() in - * order to detect signals that arrived between when the caller - * blocked signals and when he called Curl_pselect(). - * - * Curl_select() is for callers who want us to ignore caught signals and - * wait until a socket is ready or the timeout expires. We implement that - * simply as a loop around Curl_pselect(). - * - * There is a way to add signal interruptibility to poll(), which we - * don't provide today: Let caller give us a file descriptor to add - * to our list of wait-for-readable file descriptors. Caller passes - * us the fd of a pipe. He doesn't block signals and his signal - * handler writes to the other end of that pipe. Therefore, a signal - * causes poll() to return, even if received before poll() was - * called. - */ - #if defined(USE_WINSOCK) || defined(TPF) #define VERIFY_SOCK(x) do { } while (0) #else @@ -115,56 +66,18 @@ #endif /* - * This function unblocks a set of signal classes momentarily, to allow any - * the process to receive any presently blocked signal. If there exists - * a handler for that, it will run now. If not, it will typically - * terminate the process. - * - * We return 1 if as a result of the unblocking, a signal was - * received, caught and handled. 0 otherwise. + * 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. * - * On a system that does not have pselect(), we always return 0, even if - * signals were received. + * Return values: + * -1 = system call error + * 0 = timeout + * CSELECT_IN | CSELECT_OUT | CSELECT_ERR */ -int receive_signals(sigset_t * sigmask) +int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms) { -#ifdef HAVE_PSELECT - struct timespec zeroTime = {0, 0}; - - /* Note that on older Linux, pselect() is imperfect -- the kernel doesn't - have a pselect() system call, so the GNU C Library implements it - with sigprocmask() followed by select(), which means the result is - the same as with the code below for systmes with no pselect() at all. - */ - if (pselect(0, NULL, NULL, NULL, &zeroTime, sigmask) == 0) - return 0; - else - return 1; -#else - sigset_t oldmask; - - sigprocmask(SIG_SETMASK, sigmask, &oldmask); - sigprocmask(SIG_SETMASK, &oldmask, NULL); - - return 0; -#endif -} - #if defined(HAVE_POLL_FINE) || defined(CURL_HAVE_WSAPOLL) - #define USE_POLL_FOR_SELECT 1 -#else - #if defined(HAVE_SELECT) - #define USE_POLL_FOR_SELECT 0 - #else - #error "You don't appear to have either poll() or select()." - #endif -#endif - -#if USE_POLL_FOR_SELECT - -static int select_with_poll(curl_socket_t readfd, curl_socket_t writefd, - int timeout_ms) -{ struct pollfd pfd[2]; int num; int r; @@ -182,11 +95,13 @@ static int select_with_poll(curl_socket_t readfd, curl_socket_t writefd, num++; } + do { #ifdef CURL_HAVE_WSAPOLL - r = WSAPoll(pfd, num, timeout_ms); + r = WSAPoll(pfd, num, timeout_ms); #else - r = poll(pfd, num, timeout_ms); + r = poll(pfd, num, timeout_ms); #endif + } while((r == -1) && (SOCKERRNO == EINTR)); if (r < 0) return -1; @@ -217,13 +132,7 @@ static int select_with_poll(curl_socket_t readfd, curl_socket_t writefd, } return ret; -} - -#endif USE_POLL_FOR_SELECT - -static int select_with_select(curl_socket_t readfd, curl_socket_t writefd, - int timeout_ms) -{ +#else struct timeval timeout; fd_set fds_read; fd_set fds_write; @@ -270,7 +179,9 @@ static int select_with_select(curl_socket_t readfd, curl_socket_t writefd, maxfd = writefd; } - r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); + do { + r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); + } while((r == -1) && (SOCKERRNO == EINTR)); if (r < 0) return -1; @@ -292,49 +203,7 @@ static int select_with_select(curl_socket_t readfd, curl_socket_t writefd, } return ret; -} - -/* - * 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. - * - * Return values: - * -1 = system call error, including interrupted by signal - * 0 = timeout - * CSELECT_IN | CSELECT_OUT | CSELECT_ERR - */ -int Curl_pselect(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms, - sigset_t * sigmask) -{ - int ret; - sigset_t oldmask; - - if (sigmask && receive_signals(sigmask)) { - SET_SOCKERRNO(EINTR); - ret = -1; - } else { - if (sigmask) - sigprocmask(SIG_SETMASK, sigmask, &oldmask); -#if USE_POLL_FOR_SELECT - ret = select_with_poll(readfd, writefd, timeout_ms); -#else - ret = select_with_select(readfd, writefd, timeout_ms); #endif - if (sigmask) - sigprocmask(SIG_SETMASK, &oldmask, NULL); - } - return ret; -} - -int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms) -{ - int r; - do { - r = Curl_pselect(readfd, writefd, timeout_ms, NULL); - } while((r == -1) && (SOCKERRNO == EINTR)); - - return r; } /* |