summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-10-17 18:10:55 (GMT)
committerGitHub <noreply@github.com>2024-10-17 18:10:55 (GMT)
commitd8c864816121547338efa43c56e3f75ead98a924 (patch)
tree6930c118c844cd4050a5d1c025974d98f4dbc734
parentb454662921fd3a1fc27169e91aca03aadea08817 (diff)
downloadcpython-d8c864816121547338efa43c56e3f75ead98a924.zip
cpython-d8c864816121547338efa43c56e3f75ead98a924.tar.gz
cpython-d8c864816121547338efa43c56e3f75ead98a924.tar.bz2
gh-125541: Make Ctrl-C interrupt `threading.Lock.acquire()` on Windows (#125546)
-rw-r--r--Doc/library/_thread.rst9
-rw-r--r--Doc/library/threading.rst3
-rw-r--r--Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst4
-rw-r--r--Python/parking_lot.c17
4 files changed, 25 insertions, 8 deletions
diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
index 6a66fc4..ed29ac7 100644
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -187,6 +187,9 @@ Lock objects have the following methods:
.. versionchanged:: 3.2
Lock acquires can now be interrupted by signals on POSIX.
+ .. versionchanged:: 3.14
+ Lock acquires can now be interrupted by signals on Windows.
+
.. method:: lock.release()
@@ -219,12 +222,6 @@ In addition to these methods, lock objects can also be used via the
* Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
equivalent to calling :func:`_thread.exit`.
-* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method
- on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception
- will happen immediately, rather than only after the lock has been acquired or
- the operation has timed out). It can be interrupted on POSIX, but not on
- Windows.
-
* When the main thread exits, it is system defined whether the other threads
survive. On most systems, they are killed without executing
:keyword:`try` ... :keyword:`finally` clauses or executing object
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index cb82fea..d4b343d 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -567,6 +567,9 @@ All methods are executed atomically.
Lock acquisition can now be interrupted by signals on POSIX if the
underlying threading implementation supports it.
+ .. versionchanged:: 3.14
+ Lock acquisition can now be interrupted by signals on Windows.
+
.. method:: release()
diff --git a/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst b/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst
new file mode 100644
index 0000000..7a20bca
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-15-16-50-03.gh-issue-125541.FfhmWo.rst
@@ -0,0 +1,4 @@
+Pressing :kbd:`Ctrl-C` while blocked in :meth:`threading.Lock.acquire`,
+:meth:`threading.RLock.acquire`, and :meth:`threading.Thread.join` now
+interrupts the function call and raises a :exc:`KeyboardInterrupt` exception
+on Windows, similar to how those functions behave on macOS and Linux.
diff --git a/Python/parking_lot.c b/Python/parking_lot.c
index a7e9760..bffc959 100644
--- a/Python/parking_lot.c
+++ b/Python/parking_lot.c
@@ -111,15 +111,28 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, PyTime_t timeout)
millis = (DWORD) div;
}
}
- wait = WaitForSingleObjectEx(sema->platform_sem, millis, FALSE);
+
+ // NOTE: we wait on the sigint event even in non-main threads to match the
+ // behavior of the other platforms. Non-main threads will ignore the
+ // Py_PARK_INTR result.
+ HANDLE sigint_event = _PyOS_SigintEvent();
+ HANDLE handles[2] = { sema->platform_sem, sigint_event };
+ DWORD count = sigint_event != NULL ? 2 : 1;
+ wait = WaitForMultipleObjects(count, handles, FALSE, millis);
if (wait == WAIT_OBJECT_0) {
res = Py_PARK_OK;
}
+ else if (wait == WAIT_OBJECT_0 + 1) {
+ ResetEvent(sigint_event);
+ res = Py_PARK_INTR;
+ }
else if (wait == WAIT_TIMEOUT) {
res = Py_PARK_TIMEOUT;
}
else {
- res = Py_PARK_INTR;
+ _Py_FatalErrorFormat(__func__,
+ "unexpected error from semaphore: %u (error: %u)",
+ wait, GetLastError());
}
#elif defined(_Py_USE_SEMAPHORES)
int err;