mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
kunit: tool: Terminate kernel under test on SIGINT
kunit.py will attempt to catch SIGINT / ^C in order to ensure the TTY isn't messed up, but never actually attempts to terminate the running kernel (be it UML or QEMU). This can lead to a bit of frustration if the kernel has crashed or hung. Terminate the kernel process in the signal handler, if it's running. This requires plumbing through the process handle in a few more places (and having some checks to see if the kernel is still running in places where it may have already been killed). Reported-by: Andy Shevchenko <andriy.shevchenko@intel.com> Closes: https://lore.kernel.org/all/aaFmiAmg9S18EANA@smile.fi.intel.com/ Signed-off-by: David Gow <david@davidgow.net> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> Tested-by: Andy Shevchenko <andriy.shevchenko@intel.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -364,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()
|
||||
self._restore_terminal_if_tty()
|
||||
|
||||
def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
|
||||
logging.error('Build interruption occurred. Cleaning console.')
|
||||
if self._process:
|
||||
self._process.terminate()
|
||||
self._process.wait()
|
||||
self._restore_terminal_if_tty()
|
||||
|
||||
Reference in New Issue
Block a user