From e04ec66a2713e119e535e98f3f30a4e1f2bb6540 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Oct 2021 10:29:13 +0200 Subject: [PATCH] bpo-41710: Fix PY_TIMEOUT_MAX value on Windows Fix _thread.TIMEOUT_MAX value on Windows: the maximum timeout is 0x7FFFFFFF milliseconds (around 24.9 days), not 0xFFFFFFFF milliseconds (around 49.7 days). Set PY_TIMEOUT_MAX to 0x7FFFFFFF milliseconds, rather than 0xFFFFFFFF milliseconds. --- Include/pythread.h | 8 +++++--- .../Library/2021-09-30-08-57-50.bpo-41710.JMsPAW.rst | 3 +++ Python/thread_nt.h | 12 +++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-09-30-08-57-50.bpo-41710.JMsPAW.rst diff --git a/Include/pythread.h b/Include/pythread.h index bb9d86412218ad..cf4cc9a7473f1a 100644 --- a/Include/pythread.h +++ b/Include/pythread.h @@ -61,9 +61,11 @@ PyAPI_FUNC(int) _PyThread_at_fork_reinit(PyThread_type_lock *lock); convert microseconds to nanoseconds. */ # define PY_TIMEOUT_MAX (LLONG_MAX / 1000) #elif defined (NT_THREADS) - /* In the NT API, the timeout is a DWORD and is expressed in milliseconds */ -# if 0xFFFFFFFFLL * 1000 < LLONG_MAX -# define PY_TIMEOUT_MAX (0xFFFFFFFFLL * 1000) + /* In the NT API, the timeout is a DWORD and is expressed in milliseconds, + * a positive number between 0 and 0x7FFFFFFF (see WaitForSingleObject() + * documentation). */ +# if 0x7FFFFFFFLL * 1000 < LLONG_MAX +# define PY_TIMEOUT_MAX (0x7FFFFFFFLL * 1000) # else # define PY_TIMEOUT_MAX LLONG_MAX # endif diff --git a/Misc/NEWS.d/next/Library/2021-09-30-08-57-50.bpo-41710.JMsPAW.rst b/Misc/NEWS.d/next/Library/2021-09-30-08-57-50.bpo-41710.JMsPAW.rst new file mode 100644 index 00000000000000..516214a619e8eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-09-30-08-57-50.bpo-41710.JMsPAW.rst @@ -0,0 +1,3 @@ +Fix :data:`_thread.TIMEOUT_MAX` value on Windows: the maximum timeout is +0x7FFFFFFF milliseconds (around 24.9 days), not 0xFFFFFFFF milliseconds (around +49.7 days). diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 0ce5e94f89bf72..05ade1946aa373 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -295,6 +295,10 @@ PyThread_free_lock(PyThread_type_lock aLock) FreeNonRecursiveMutex(aLock) ; } +// WaitForSingleObject() documentation: "The time-out value needs to be a +// positive number between 0 and 0x7FFFFFFF." INFINITE is equal to 0xFFFFFFFF. +const DWORD TIMEOUT_MS_MAX = 0x7FFFFFFF; + /* * Return 1 on success if the lock was acquired * @@ -312,9 +316,11 @@ PyThread_acquire_lock_timed(PyThread_type_lock aLock, if (microseconds >= 0) { milliseconds = microseconds / 1000; - if (microseconds % 1000 > 0) - ++milliseconds; - if (milliseconds > PY_DWORD_MAX) { + // Round milliseconds away from zero + if (microseconds % 1000 > 0) { + milliseconds++; + } + if (milliseconds > (PY_TIMEOUT_T)TIMEOUT_MS_MAX) { Py_FatalError("Timeout larger than PY_TIMEOUT_MAX"); } }