Skip to content

Commit 1026d8d

Browse files
author
And Clover
committed
bpo-39847: don't over-wait for mutex on win32 at tickcount overflow
The 32-bit (49-day) TickCount relied on in EnterNonRecursiveMutex can overflow in the gap between the 'target' time and the 'now' time WaitForSingleObjectEx returns, causing the loop to think it needs to wait another 49 days. This is most likely to happen when the machine is hibernated during WaitForSingleObjectEx. This makes acquiring a lock/event/etc from the _thread or threading module appear to never timeout. Replace with GetTickCount64 - this is OK now we no longer support XP which lacks it, and is in use for time.monotonic. Approaches not taken: - forcing signed arithmetic for the now/target comparison (this would only partially solve the problem with GetTickCount as you could still break it by hibernating for 24 days; it's unnecessary for 64-bit which takes however many hundred million years to roll over)
1 parent dffe4c0 commit 1026d8d

File tree

2 files changed

+5
-3
lines changed

2 files changed

+5
-3
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid hang when computer is hibernated whilst waiting for a mutex (for
2+
lock-related objects from :mod:`threading`) around 49-day uptime.

Python/thread_nt.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,16 @@ EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds)
7575
}
7676
} else if (milliseconds != 0) {
7777
/* wait at least until the target */
78-
DWORD now, target = GetTickCount() + milliseconds;
78+
ULONGLONG now, target = GetTickCount64() + milliseconds;
7979
while (mutex->locked) {
8080
if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, (long long)milliseconds*1000) < 0) {
8181
result = WAIT_FAILED;
8282
break;
8383
}
84-
now = GetTickCount();
84+
now = GetTickCount64();
8585
if (target <= now)
8686
break;
87-
milliseconds = target-now;
87+
milliseconds = (DWORD)(target-now);
8888
}
8989
}
9090
if (!mutex->locked) {

0 commit comments

Comments
 (0)