summaryrefslogtreecommitdiff
path: root/test/lib/ansible_test/_util/target/sanity/import/importer.py
diff options
context:
space:
mode:
authorMatt Davis <6775756+nitzmahone@users.noreply.github.com>2022-12-05 20:46:15 -0800
committerGitHub <noreply@github.com>2022-12-05 20:46:15 -0800
commit1424484be0e1b9a1d1e7e1849ae1a5e2a19d612c (patch)
treed14e1296fc4ecf6202d78b79e6262c0c1728c000 /test/lib/ansible_test/_util/target/sanity/import/importer.py
parent80d2f8da02052f64396da6b8caaf820eedbf18e2 (diff)
downloadansible-1424484be0e1b9a1d1e7e1849ae1a5e2a19d612c.tar.gz
Prevent stdio deadlock in forked children (#79522)
* background threads writing to stdout/stderr can cause children to deadlock if a thread in the parent holds the internal lock on the BufferedWriter wrapper * prevent writes to std handles during fork by monkeypatching stdout/stderr during display startup to require a mutex lock with fork(); this ensures no background threads can hold the lock during a fork operation * add integration test that fails reliably on Linux without this fix
Diffstat (limited to 'test/lib/ansible_test/_util/target/sanity/import/importer.py')
-rw-r--r--test/lib/ansible_test/_util/target/sanity/import/importer.py24
1 files changed, 13 insertions, 11 deletions
diff --git a/test/lib/ansible_test/_util/target/sanity/import/importer.py b/test/lib/ansible_test/_util/target/sanity/import/importer.py
index 3dcb8bf934..3180530c95 100644
--- a/test/lib/ansible_test/_util/target/sanity/import/importer.py
+++ b/test/lib/ansible_test/_util/target/sanity/import/importer.py
@@ -48,11 +48,7 @@ def main():
__import__(name)
return sys.modules[name]
- try:
- # noinspection PyCompatibility
- from StringIO import StringIO
- except ImportError:
- from io import StringIO
+ from io import BytesIO, TextIOWrapper
try:
from importlib.util import spec_from_loader, module_from_spec
@@ -436,8 +432,9 @@ def main():
class Capture:
"""Captured output and/or exception."""
def __init__(self):
- self.stdout = StringIO()
- self.stderr = StringIO()
+ # use buffered IO to simulate StringIO; allows Ansible's stream patching to behave without warnings
+ self.stdout = TextIOWrapper(BytesIO())
+ self.stderr = TextIOWrapper(BytesIO())
def capture_report(path, capture, messages):
"""Report on captured output.
@@ -445,12 +442,17 @@ def main():
:type capture: Capture
:type messages: set[str]
"""
- if capture.stdout.getvalue():
- first = capture.stdout.getvalue().strip().splitlines()[0].strip()
+ # since we're using buffered IO, flush before checking for data
+ capture.stdout.flush()
+ capture.stderr.flush()
+ stdout_value = capture.stdout.buffer.getvalue()
+ if stdout_value:
+ first = stdout_value.decode().strip().splitlines()[0].strip()
report_message(path, 0, 0, 'stdout', first, messages)
- if capture.stderr.getvalue():
- first = capture.stderr.getvalue().strip().splitlines()[0].strip()
+ stderr_value = capture.stderr.buffer.getvalue()
+ if stderr_value:
+ first = stderr_value.decode().strip().splitlines()[0].strip()
report_message(path, 0, 0, 'stderr', first, messages)
def report_message(path, line, column, code, message, messages):