]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-139391: properly handle `signal.signal()` in `UnixConsole` when called...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 9 Oct 2025 16:10:51 +0000 (18:10 +0200)
committerGitHub <noreply@github.com>
Thu, 9 Oct 2025 16:10:51 +0000 (16:10 +0000)
gh-139391: properly handle `signal.signal()` in `UnixConsole` when called from a non-main thread (GH-139392)
(cherry picked from commit b8c8b8f1d30767e5358ffa93d41e6e27ca60570d)

Co-authored-by: yihong <zouzou0208@gmail.com>
Lib/_pyrepl/unix_console.py
Lib/test/test_pyrepl/test_unix_console.py
Misc/NEWS.d/next/Library/2025-09-28-16-34-11.gh-issue-139391.nRFnmx.rst [new file with mode: 0644]

index fe45b4eb3840679732827fa6fa4e76950eaf50e1..09247de748ee3bda76c9dc612fbd44ff350e7f66 100644 (file)
@@ -390,7 +390,12 @@ class UnixConsole(Console):
             os.write(self.output_fd, b"\033[?7h")
 
         if hasattr(self, "old_sigwinch"):
-            signal.signal(signal.SIGWINCH, self.old_sigwinch)
+            try:
+                signal.signal(signal.SIGWINCH, self.old_sigwinch)
+            except ValueError as e:
+                import threading
+                if threading.current_thread() is threading.main_thread():
+                    raise e
             del self.old_sigwinch
 
     def push_char(self, char: int | bytes) -> None:
index 9ac2e9961df2dc6257d38cdde015240abb0c39be..f4fb9237ffdfd0d6139854859e9dc8b204a619bc 100644 (file)
@@ -4,11 +4,12 @@ import os
 import signal
 import subprocess
 import sys
+import threading
 import unittest
 from functools import partial
 from test import support
 from test.support import os_helper, force_not_colorized_test_class
-from test.support import script_helper
+from test.support import script_helper, threading_helper
 
 from unittest import TestCase
 from unittest.mock import MagicMock, call, patch, ANY, Mock
@@ -318,6 +319,17 @@ class TestConsole(TestCase):
             console.prepare()  # needed to call restore()
             console.restore()  # this should succeed
 
+    @threading_helper.reap_threads
+    @threading_helper.requires_working_threading()
+    def test_restore_in_thread(self, _os_write):
+        # gh-139391: ensure that console.restore() silently suppresses
+        # exceptions when calling signal.signal() from a non-main thread.
+        console = unix_console([])
+        console.old_sigwinch = signal.SIG_DFL
+        thread = threading.Thread(target=console.restore)
+        thread.start()
+        thread.join()  # this should not raise
+
 
 @unittest.skipIf(sys.platform == "win32", "No Unix console on Windows")
 class TestUnixConsoleEIOHandling(TestCase):
diff --git a/Misc/NEWS.d/next/Library/2025-09-28-16-34-11.gh-issue-139391.nRFnmx.rst b/Misc/NEWS.d/next/Library/2025-09-28-16-34-11.gh-issue-139391.nRFnmx.rst
new file mode 100644 (file)
index 0000000..93d1ce6
--- /dev/null
@@ -0,0 +1,3 @@
+Fix an issue when, on non-Windows platforms, it was not possible to
+gracefully exit a ``python -m asyncio`` process suspended by Ctrl+Z
+and later resumed by :manpage:`fg` other than with :manpage:`kill`.