Use poll() instead of select() inside redisContextWaitReady()

The current select() is limiting in instances where the fd num is > FD_SETSIZE.
Since redisContextWaitReady() only processes a single fd, select would still
fail.

For compatibility reasons I have converted select() over to poll(), eliminating
this problem.
This commit is contained in:
Mark Ellzey 2012-02-21 18:20:29 -05:00 committed by Pieter Noordhuis
parent 857b2690af
commit f8debbfdbe

40
net.c
View File

@ -45,6 +45,8 @@
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <poll.h>
#include <limits.h>
#include "net.h" #include "net.h"
#include "sds.h" #include "sds.h"
@ -121,28 +123,38 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
return REDIS_OK; return REDIS_OK;
} }
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) { static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) {
struct timeval to; struct pollfd wfd[1];
struct timeval *toptr = NULL; long msec;
fd_set wfd;
msec = -1;
wfd[0].fd = fd;
wfd[0].events = POLLOUT;
/* Only use timeout when not NULL. */ /* Only use timeout when not NULL. */
if (timeout != NULL) { if (timeout != NULL) {
to = *timeout; if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
toptr = &to;
}
if (errno == EINPROGRESS) {
FD_ZERO(&wfd);
FD_SET(fd, &wfd);
if (select(FD_SETSIZE, NULL, &wfd, NULL, toptr) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"select(2)");
close(fd); close(fd);
return REDIS_ERR; return REDIS_ERR;
} }
if (!FD_ISSET(fd, &wfd)) { msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000);
if (msec < 0 || msec > INT_MAX) {
msec = INT_MAX;
}
}
if (errno == EINPROGRESS) {
int res;
if ((res = poll(wfd, 1, msec)) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
close(fd);
return REDIS_ERR;
} else if (res == 0) {
errno = ETIMEDOUT; errno = ETIMEDOUT;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
close(fd); close(fd);