summaryrefslogtreecommitdiff
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
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
-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) {