From f8debbfdbebb97f5d0ee2218edf1425ac219cff5 Mon Sep 17 00:00:00 2001 From: Mark Ellzey Date: Tue, 21 Feb 2012 18:20:29 -0500 Subject: [PATCH] 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. --- net.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/net.c b/net.c index 158e1dd..82ab2b4 100644 --- a/net.c +++ b/net.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include "net.h" #include "sds.h" @@ -121,28 +123,38 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) { return REDIS_OK; } +#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) + static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) { - struct timeval to; - struct timeval *toptr = NULL; - fd_set wfd; + struct pollfd wfd[1]; + long msec; + + msec = -1; + wfd[0].fd = fd; + wfd[0].events = POLLOUT; /* Only use timeout when not NULL. */ if (timeout != NULL) { - to = *timeout; - 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)"); + if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { close(fd); 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; __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); close(fd);