Commit af955176 authored by michael-grunder's avatar michael-grunder Committed by Michael Grunder
Browse files

Retry poll(2) if we are intterupted.

This commit adds logic to retry our poll call when waiting for the
connection to complete, in the event that we are interrupted by a
signal.

Additionally we do some simple bookkeeping to keep track of the overall
timeout specified by the user.

Fixes #1206
parent dedc6208
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include "net.h" #include "net.h"
#include "sds.h" #include "sds.h"
...@@ -271,37 +272,54 @@ static int redisContextTimeoutMsec(redisContext *c, long *result) ...@@ -271,37 +272,54 @@ static int redisContextTimeoutMsec(redisContext *c, long *result)
return REDIS_OK; return REDIS_OK;
} }
static long redisPollMillis(void) {
#ifndef _MSC_VER
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (now.tv_sec * 1000) + now.tv_nsec / 1000000;
#else
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime) / 10;
#endif
}
static int redisContextWaitReady(redisContext *c, long msec) { static int redisContextWaitReady(redisContext *c, long msec) {
struct pollfd wfd[1]; struct pollfd wfd;
long end;
int res;
wfd[0].fd = c->fd; if (errno != EINPROGRESS) {
wfd[0].events = POLLOUT; __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisNetClose(c);
return REDIS_ERR;
}
if (errno == EINPROGRESS) { wfd.fd = c->fd;
int res; wfd.events = POLLOUT;
end = msec >= 0 ? redisPollMillis() + msec : 0;
if ((res = poll(wfd, 1, msec)) == -1) { while ((res = poll(&wfd, 1, msec)) <= 0) {
if (res < 0 && errno != EINTR) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
redisNetClose(c); redisNetClose(c);
return REDIS_ERR; return REDIS_ERR;
} else if (res == 0) { } else if (res == 0 || (msec >= 0 && redisPollMillis() >= end)) {
errno = ETIMEDOUT; errno = ETIMEDOUT;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
redisNetClose(c); redisNetClose(c);
return REDIS_ERR; return REDIS_ERR;
} else {
/* res < 0 && errno == EINTR, try again */
} }
}
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) { if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
redisCheckSocketError(c); redisCheckSocketError(c);
return REDIS_ERR; return REDIS_ERR;
}
return REDIS_OK;
} }
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); return REDIS_OK;
redisNetClose(c);
return REDIS_ERR;
} }
int redisCheckConnectDone(redisContext *c, int *completed) { int redisCheckConnectDone(redisContext *c, int *completed) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment