summaryrefslogtreecommitdiff
path: root/tools/testing/kunit/kunit_kernel.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/kunit/kunit_kernel.py')
-rw-r--r--tools/testing/kunit/kunit_kernel.py40
1 files changed, 28 insertions, 12 deletions
diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
index 2998e1bc088b..58557c47d85f 100644
--- a/tools/testing/kunit/kunit_kernel.py
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -16,7 +16,7 @@ import shutil
import signal
import sys
import threading
-from typing import Iterator, List, Optional, Tuple
+from typing import Iterator, List, Optional, Tuple, Any
from types import FrameType
import kunit_config
@@ -218,7 +218,7 @@ def _get_qemu_ops(config_path: str,
# exists (I learned this through experimentation and could not find it
# anywhere in the Python documentation).
#
- # Bascially, we completely ignore the actual file location of the config
+ # Basically, we completely ignore the actual file location of the config
# we are loading and just tell Python that the module lives in the
# QEMU_CONFIGS_DIR for import purposes regardless of where it actually
# exists as a file.
@@ -265,6 +265,7 @@ class LinuxSourceTree:
if kconfig_add:
kconfig = kunit_config.parse_from_string('\n'.join(kconfig_add))
self._kconfig.merge_in_entries(kconfig)
+ self._process : Optional[subprocess.Popen[Any]] = None
def arch(self) -> str:
return self._arch
@@ -345,6 +346,12 @@ class LinuxSourceTree:
return False
return self.validate_config(build_dir)
+ def _restore_terminal_if_tty(self) -> None:
+ # stty requires a controlling terminal; skip headless runs.
+ if sys.stdin is None or not sys.stdin.isatty():
+ return
+ subprocess.call(['stty', 'sane'])
+
def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]:
# Copy to avoid mutating the caller-supplied list. exec_tests() reuses
# the same args across repeated run_kernel() calls (e.g. --run_isolated),
@@ -358,36 +365,45 @@ class LinuxSourceTree:
args.append('kunit.filter_action=' + filter_action)
args.append('kunit.enable=1')
- process = self._ops.start(args, build_dir)
- assert process.stdout is not None # tell mypy it's set
+ self._process = self._ops.start(args, build_dir)
+ assert self._process is not None # tell mypy it's set
+ assert self._process.stdout is not None # tell mypy it's set
# Enforce the timeout in a background thread.
def _wait_proc() -> None:
try:
- process.wait(timeout=timeout)
+ if self._process:
+ self._process.wait(timeout=timeout)
except Exception as e:
print(e)
- process.terminate()
- process.wait()
+ if self._process:
+ self._process.terminate()
+ self._process.wait()
waiter = threading.Thread(target=_wait_proc)
waiter.start()
output = open(get_outfile_path(build_dir), 'w')
try:
# Tee the output to the file and to our caller in real time.
- for line in process.stdout:
+ for line in self._process.stdout:
output.write(line)
yield line
# This runs even if our caller doesn't consume every line.
finally:
# Flush any leftover output to the file
- output.write(process.stdout.read())
+ if self._process:
+ if self._process.stdout:
+ output.write(self._process.stdout.read())
+ self._process.stdout.close()
+ self._process = None
output.close()
- process.stdout.close()
waiter.join()
- subprocess.call(['stty', 'sane'])
+ self._restore_terminal_if_tty()
def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
logging.error('Build interruption occurred. Cleaning console.')
- subprocess.call(['stty', 'sane'])
+ if self._process:
+ self._process.terminate()
+ self._process.wait()
+ self._restore_terminal_if_tty()