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
This commit is contained in:
parent
dedc6208b1
commit
97679e57ba
54
net.c
54
net.c
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "sds.h"
|
||||
@ -271,37 +272,54 @@ static int redisContextTimeoutMsec(redisContext *c, long *result)
|
||||
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) {
|
||||
struct pollfd wfd[1];
|
||||
struct pollfd wfd;
|
||||
long end;
|
||||
int res;
|
||||
|
||||
wfd[0].fd = c->fd;
|
||||
wfd[0].events = POLLOUT;
|
||||
if (errno != EINPROGRESS) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (errno == EINPROGRESS) {
|
||||
int res;
|
||||
wfd.fd = c->fd;
|
||||
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)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else if (res == 0) {
|
||||
} else if (res == 0 || (msec >= 0 && redisPollMillis() >= end)) {
|
||||
errno = ETIMEDOUT;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else {
|
||||
/* res < 0 && errno == EINTR, try again */
|
||||
}
|
||||
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisCheckConnectDone(redisContext *c, int *completed) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user