102 lines
2.9 KiB
Diff
102 lines
2.9 KiB
Diff
From 97679e57badd4df954e083f4aa5408d29b39785f Mon Sep 17 00:00:00 2001
|
|
From: michael-grunder <michael.grunder@gmail.com>
|
|
Date: Wed, 12 Jul 2023 14:23:07 -0700
|
|
Subject: [PATCH] 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
|
|
---
|
|
net.c | 52 +++++++++++++++++++++++++++++++++++-----------------
|
|
1 file changed, 35 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/net.c b/net.c
|
|
index 1e016384f..c7d827139 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) {
|