twister: try to clean ninja zombie

sometimes ninja fails to launch qemu, the sub-thread
can't read anything from qemu pipeline, then the
corresponding testcase will timeout. Then the
sub-thread will get blocked if it call join()

set terminate as the Handler's method, then
Handler's children class can call it

Signed-off-by: Jingru Wang <jingru@synopsys.com>
This commit is contained in:
Jingru Wang 2021-06-11 11:54:55 +08:00 committed by Anas Nashif
commit fed1c54cf2

View file

@ -400,6 +400,7 @@ class Handler:
self.generator_cmd = None
self.args = []
self.terminated = False
def set_state(self, state, duration):
self.state = state
@ -418,6 +419,23 @@ class Handler:
for instance in harness.recording:
cw.writerow(instance)
def terminate(self, proc):
# encapsulate terminate functionality so we do it consistently where ever
# we might want to terminate the proc. We need try_kill_process_by_pid
# because of both how newer ninja (1.6.0 or greater) and .NET / renode
# work. Newer ninja's don't seem to pass SIGTERM down to the children
# so we need to use try_kill_process_by_pid.
for child in psutil.Process(proc.pid).children(recursive=True):
try:
os.kill(child.pid, signal.SIGTERM)
except ProcessLookupError:
pass
proc.terminate()
# sleep for a while before attempting to kill
time.sleep(0.5)
proc.kill()
self.terminated = True
class BinaryHandler(Handler):
def __init__(self, instance, type_str):
@ -427,7 +445,6 @@ class BinaryHandler(Handler):
"""
super().__init__(instance, type_str)
self.terminated = False
self.call_west_flash = False
# Tool options
@ -447,23 +464,6 @@ class BinaryHandler(Handler):
except ProcessLookupError:
pass
def terminate(self, proc):
# encapsulate terminate functionality so we do it consistently where ever
# we might want to terminate the proc. We need try_kill_process_by_pid
# because of both how newer ninja (1.6.0 or greater) and .NET / renode
# work. Newer ninja's don't seem to pass SIGTERM down to the children
# so we need to use try_kill_process_by_pid.
for child in psutil.Process(proc.pid).children(recursive=True):
try:
os.kill(child.pid, signal.SIGTERM)
except ProcessLookupError:
pass
proc.terminate()
# sleep for a while before attempting to kill
time.sleep(0.5)
proc.kill()
self.terminated = True
def _output_reader(self, proc):
self.line = proc.stdout.readline()
@ -1123,31 +1123,22 @@ class QEMUHandler(Handler):
# twister to judge testing result by console output
is_timeout = True
if os.path.exists(self.pid_fn):
qemu_pid = int(open(self.pid_fn).read())
try:
os.kill(qemu_pid, signal.SIGKILL)
except ProcessLookupError:
pass
proc.wait()
if harness.state == "passed":
self.returncode = 0
else:
self.returncode = proc.returncode
self.terminate(proc)
if harness.state == "passed":
self.returncode = 0
else:
proc.terminate()
proc.kill()
self.returncode = proc.returncode
else:
if os.path.exists(self.pid_fn):
qemu_pid = int(open(self.pid_fn).read())
logger.debug(f"No timeout, return code from QEMU ({qemu_pid}): {proc.returncode}")
self.returncode = proc.returncode
# Need to wait for harness to finish processing
# output from QEMU. Otherwise it might miss some
# error messages.
self.thread.join()
self.thread.join(0)
if self.thread.is_alive():
logger.debug("Timed out while monitoring QEMU output")
if os.path.exists(self.pid_fn):
qemu_pid = int(open(self.pid_fn).read())