summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_io.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:41:47 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:41:47 (GMT)
commit25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f (patch)
treec6b252f8cde6d114360560f412044a5b0e46d999 /Lib/test/test_io.py
parentf3b990e48c698154fb2eaa990ee22a6962e041ac (diff)
downloadcpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.zip
cpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.tar.gz
cpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.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.py45
1 files changed, 44 insertions, 1 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 95277d9..dfa3d77 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
@@ -3350,6 +3350,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