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

openSUSE Build Service is sponsored by