File 1428-erts-Ensure-ethr_event-can-handle-huge-timeouts.patch of Package erlang
From bb02aa139d19e3992de7eb7d282b323e9bf26b0e Mon Sep 17 00:00:00 2001
From: Rickard Green <rickard@erlang.org>
Date: Sat, 23 Dec 2023 22:35:24 +0100
Subject: [PATCH 2/3] [erts] Ensure ethr_event can handle huge timeouts
---
erts/include/internal/erl_errno.h | 3 +++
erts/lib_src/pthread/ethr_event.c | 41 ++++++++++++++++++++++++++-----
erts/lib_src/win/ethr_event.c | 15 +++++++++--
3 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/erts/include/internal/erl_errno.h b/erts/include/internal/erl_errno.h
index 1ae045805e..dad9e36a90 100644
--- a/erts/include/internal/erl_errno.h
+++ b/erts/include/internal/erl_errno.h
@@ -47,6 +47,9 @@
# ifndef ETIMEDOUT
# define ETIMEDOUT EAGAIN
# endif
+# ifndef EINTR
+# define EINTR (INT_MAX-1)
+# endif
#endif
#endif
diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c
index 26f4da7d60..6b6235122a 100644
--- a/erts/lib_src/pthread/ethr_event.c
+++ b/erts/lib_src/pthread/ethr_event.c
@@ -52,6 +52,7 @@
#include <sched.h>
#include <errno.h>
+#include <limits.h>
#define ETHR_YIELD_AFTER_BUSY_LOOPS 50
@@ -92,6 +93,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
ethr_sint64_t start = 0; /* SHUT UP annoying faulty warning... */
#endif
+ int timeout_res = ETIMEDOUT;
if (spincount < 0)
ETHR_FATAL_ERROR__(EINVAL);
@@ -131,6 +133,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
}
if (timeout >= 0) {
+ ethr_sint64_t sec, nsec;
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
time = timeout - (ethr_get_monotonic_time() - start);
#endif
@@ -141,8 +144,18 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
goto return_event_on;
return ETIMEDOUT;
}
- ts.tv_sec = time / (1000*1000*1000);
- ts.tv_nsec = time % (1000*1000*1000);
+ sec = time / (1000*1000*1000);
+ nsec = time % (1000*1000*1000);
+ if (sizeof(ts.tv_sec) == 8
+ || sec <= (ethr_sint64_t) INT_MAX) {
+ ts.tv_sec = sec;
+ ts.tv_nsec = nsec;
+ }
+ else {
+ ts.tv_sec = INT_MAX;
+ ts.tv_nsec = 0;
+ timeout_res = EINTR;
+ }
}
if (val != ETHR_EVENT_OFF_WAITER__) {
@@ -160,8 +173,10 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
ETHR_EVENT_OFF_WAITER__,
tsp);
switch (res) {
- case EINTR:
case ETIMEDOUT:
+ res = timeout_res;
+ /* Fall through... */
+ case EINTR:
return res;
case 0:
case EWOULDBLOCK:
@@ -189,6 +204,7 @@ return_event_on:
#include <sys/select.h>
#include <errno.h>
#include <string.h>
+#include <limits.h>
#include "erl_misc_utils.h"
@@ -358,6 +374,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
ethr_sint64_t timeout_time = 0; /* SHUT UP annoying faulty warning... */
#endif
+ int timeout_res = ETIMEDOUT;
val = ethr_atomic32_read(&e->state);
if (val == ETHR_EVENT_ON__)
@@ -452,6 +469,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
if (timeout > 0) {
if (time != timeout_time) {
+ ethr_sint64_t sec, nsec;
time = timeout_time;
#if ERTS_USE_PREMATURE_TIMEOUT
@@ -467,11 +485,22 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
time -= ERTS_PREMATURE_TIMEOUT(rtmo, 1000*1000*1000);
}
#endif
-
- cond_timeout.tv_sec = time / (1000*1000*1000);
- cond_timeout.tv_nsec = time % (1000*1000*1000);
+ sec = time / (1000*1000*1000);
+ nsec = time % (1000*1000*1000);
+ if (sizeof(cond_timeout.tv_sec) == 8
+ || sec <= (ethr_sint64_t) INT_MAX) {
+ cond_timeout.tv_sec = sec;
+ cond_timeout.tv_nsec = nsec;
+ }
+ else {
+ cond_timeout.tv_sec = INT_MAX;
+ cond_timeout.tv_nsec = 0;
+ timeout_res = EINTR;
+ }
}
res = pthread_cond_timedwait(&e->cnd, &e->mtx, &cond_timeout);
+ if (res == ETIMEDOUT)
+ res = timeout_res;
if (res == EINTR
|| (res == ETIMEDOUT
#if ERTS_USE_PREMATURE_TIMEOUT
diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c
index 383f7c876e..d03c6342cc 100644
--- a/erts/lib_src/win/ethr_event.c
+++ b/erts/lib_src/win/ethr_event.c
@@ -71,11 +71,14 @@ ethr_event_reset(ethr_event *e)
ethr_event_reset__(e);
}
+#define MILLISECONDS_PER_WEEK__ (7*24*60*60*1000)
+
static ETHR_INLINE int
wait(ethr_event *e, int spincount, ethr_sint64_t timeout)
{
DWORD code, tmo;
int sc, res, until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ int timeout_res = ETIMEDOUT;
if (timeout < 0)
tmo = INFINITE;
@@ -88,11 +91,19 @@ wait(ethr_event *e, int spincount, ethr_sint64_t timeout)
return ETIMEDOUT;
}
else {
+ ethr_sint64_t tmo_ms;
/*
* Timeout in nano-seconds, but we can only
* wait for milli-seconds...
*/
- tmo = (DWORD) (timeout - 1) / (1000*1000) + 1;
+ tmo_ms = (timeout - 1) / (1000*1000) + 1;
+ if (tmo_ms <= MILLISECONDS_PER_WEEK__) {
+ tmo = (DWORD) tmo_ms;
+ }
+ else {
+ tmo = MILLISECONDS_PER_WEEK__;
+ timeout_res = EINTR;
+ }
}
if (spincount < 0)
@@ -131,7 +142,7 @@ wait(ethr_event *e, int spincount, ethr_sint64_t timeout)
code = WaitForSingleObject(e->handle, tmo);
if (code == WAIT_TIMEOUT)
- return ETIMEDOUT;
+ return timeout_res;
if (code != WAIT_OBJECT_0)
ETHR_FATAL_ERROR__(ethr_win_get_errno__());
}
--
2.35.3