Skip to content

Commit 8761d6e

Browse files
[3.14] gh-139391: properly handle signal.signal() in UnixConsole when called from a non-main thread (GH-139392) (#139858)
gh-139391: properly handle `signal.signal()` in `UnixConsole` when called from a non-main thread (GH-139392) (cherry picked from commit b8c8b8f) Co-authored-by: yihong <[email protected]>
1 parent de87549 commit 8761d6e

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

Lib/_pyrepl/unix_console.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,12 @@ def restore(self):
390390
os.write(self.output_fd, b"\033[?7h")
391391

392392
if hasattr(self, "old_sigwinch"):
393-
signal.signal(signal.SIGWINCH, self.old_sigwinch)
393+
try:
394+
signal.signal(signal.SIGWINCH, self.old_sigwinch)
395+
except ValueError as e:
396+
import threading
397+
if threading.current_thread() is threading.main_thread():
398+
raise e
394399
del self.old_sigwinch
395400

396401
def push_char(self, char: int | bytes) -> None:

Lib/test/test_pyrepl/test_unix_console.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import signal
55
import subprocess
66
import sys
7+
import threading
78
import unittest
89
from functools import partial
910
from test import support
1011
from test.support import os_helper, force_not_colorized_test_class
11-
from test.support import script_helper
12+
from test.support import script_helper, threading_helper
1213

1314
from unittest import TestCase
1415
from unittest.mock import MagicMock, call, patch, ANY, Mock
@@ -318,6 +319,17 @@ def test_restore_with_invalid_environ_on_macos(self, _os_write):
318319
console.prepare() # needed to call restore()
319320
console.restore() # this should succeed
320321

322+
@threading_helper.reap_threads
323+
@threading_helper.requires_working_threading()
324+
def test_restore_in_thread(self, _os_write):
325+
# gh-139391: ensure that console.restore() silently suppresses
326+
# exceptions when calling signal.signal() from a non-main thread.
327+
console = unix_console([])
328+
console.old_sigwinch = signal.SIG_DFL
329+
thread = threading.Thread(target=console.restore)
330+
thread.start()
331+
thread.join() # this should not raise
332+
321333

322334
@unittest.skipIf(sys.platform == "win32", "No Unix console on Windows")
323335
class TestUnixConsoleEIOHandling(TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an issue when, on non-Windows platforms, it was not possible to
2+
gracefully exit a ``python -m asyncio`` process suspended by Ctrl+Z
3+
and later resumed by :manpage:`fg` other than with :manpage:`kill`.

0 commit comments

Comments
 (0)