Skip to content

Commit ff0455e

Browse files
committed
pythongh-125541: Make Ctrl-C interrupt threading.Lock.acquire() on Windows
1 parent aac89b5 commit ff0455e

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

Doc/library/_thread.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ Lock objects have the following methods:
187187
.. versionchanged:: 3.2
188188
Lock acquires can now be interrupted by signals on POSIX.
189189

190+
.. versionchanged:: 3.14
191+
Lock acquires can now be interrupted by signals on Windows.
192+
190193

191194
.. method:: lock.release()
192195

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Pressing :kbd:`Ctrl-C` while blocked in :meth:`threading.Lock.acquire` now
2+
interrupts the function and raises a :exc:`KeyboardInterrupt` exception on
3+
Windows, similar to how it behaves on macOS and Linux.

Python/parking_lot.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,27 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout)
111111
millis = (DWORD) div;
112112
}
113113
}
114-
wait = WaitForSingleObjectEx(sema->platform_sem, millis, FALSE);
114+
115+
// NOTE: we wait on the sigint event even in non-main threads to match the
116+
// behavior of the other platforms. Non-main threads will ignore the
117+
// Py_PARK_INTR result.
118+
HANDLE sigint_event = _PyOS_SigintEvent();
119+
HANDLE handles[2] = {sema->platform_sem, sigint_event};
120+
wait = WaitForMultipleObjectsEx(2, handles, FALSE, millis, FALSE);
115121
if (wait == WAIT_OBJECT_0) {
116122
res = Py_PARK_OK;
117123
}
124+
else if (wait == WAIT_OBJECT_0 + 1) {
125+
ResetEvent(sigint_event);
126+
res = Py_PARK_INTR;
127+
}
118128
else if (wait == WAIT_TIMEOUT) {
119129
res = Py_PARK_TIMEOUT;
120130
}
121131
else {
122-
res = Py_PARK_INTR;
132+
_Py_FatalErrorFormat(__func__,
133+
"unexpected error from semaphore: %u (error: %u)",
134+
wait, GetLastError());
123135
}
124136
#elif defined(_Py_USE_SEMAPHORES)
125137
int err;

0 commit comments

Comments
 (0)