summaryrefslogtreecommitdiff
path: root/net.c
diff options
context:
space:
mode:
authormichael-grunder <michael.grunder@gmail.com>2023-07-12 14:23:07 -0700
committerMichael Grunder <michael.grunder@gmail.com>2023-07-25 10:24:06 -0700
commitaf95517612c209976352201f5f8f302bf9aef876 (patch)
tree09f30a641a152987e98f15615ffd90a8a47c5beb /net.c
parentdedc6208b15738d7765eff35a61dd09d5830e732 (diff)
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
Diffstat (limited to 'net.c')
-rw-r--r--net.c52
1 files changed, 35 insertions, 17 deletions
diff --git a/net.c b/net.c
index 1e01638..c7d8271 100644
--- a/net.c
+++ b/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;
+ if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
+ redisCheckSocketError(c);
+ return REDIS_ERR;
}
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
- redisNetClose(c);
- return REDIS_ERR;
+ return REDIS_OK;
}
int redisCheckConnectDone(redisContext *c, int *completed) {