diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2015-04-13 17:48:19 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2015-04-13 17:48:19 (GMT) |
commit | cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a (patch) | |
tree | bd7bf53350b0acbd12721bcfba898d6f6072fc1c /Lib/test/test_io.py | |
parent | 9c680b07285867844927871ddcbf60c93e786e1f (diff) | |
parent | 25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f (diff) | |
download | cpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.zip cpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.tar.gz cpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.tar.bz2 |
Issue #23309: Avoid a deadlock at shutdown if a daemon thread is aborted
while it is holding a lock to a buffered I/O object, and the main thread
tries to use the same I/O object (typically stdout or stderr). A fatal
error is emitted instead.
Diffstat (limited to 'Lib/test/test_io.py')
-rw-r--r-- | Lib/test/test_io.py | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 9fb85f2..2d02a31 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -35,7 +35,7 @@ import weakref from collections import deque, UserList from itertools import cycle, count from test import support -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, run_python_until_end import codecs import io # C implementation of io @@ -3437,6 +3437,49 @@ class CMiscIOTest(MiscIOTest): b = bytearray(2) self.assertRaises(ValueError, bufio.readinto, b) + @unittest.skipUnless(threading, 'Threading required for this test.') + def check_daemon_threads_shutdown_deadlock(self, stream_name): + # Issue #23309: deadlocks at shutdown should be avoided when a + # daemon thread and the main thread both write to a file. + code = """if 1: + import sys + import time + import threading + + file = sys.{stream_name} + + def run(): + while True: + file.write('.') + file.flush() + + thread = threading.Thread(target=run) + thread.daemon = True + thread.start() + + time.sleep(0.5) + file.write('!') + file.flush() + """.format_map(locals()) + res, _ = run_python_until_end("-c", code) + err = res.err.decode() + if res.rc != 0: + # Failure: should be a fatal error + self.assertIn("Fatal Python error: could not acquire lock " + "for <_io.BufferedWriter name='<{stream_name}>'> " + "at interpreter shutdown, possibly due to " + "daemon threads".format_map(locals()), + err) + else: + self.assertFalse(err.strip('.!')) + + def test_daemon_threads_shutdown_stdout_deadlock(self): + self.check_daemon_threads_shutdown_deadlock('stdout') + + def test_daemon_threads_shutdown_stderr_deadlock(self): + self.check_daemon_threads_shutdown_deadlock('stderr') + + class PyMiscIOTest(MiscIOTest): io = pyio |