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:
parent
2d2bc55f51
commit
fed1c54cf2
1 changed files with 24 additions and 33 deletions
|
@ -400,6 +400,7 @@ class Handler:
|
||||||
self.generator_cmd = None
|
self.generator_cmd = None
|
||||||
|
|
||||||
self.args = []
|
self.args = []
|
||||||
|
self.terminated = False
|
||||||
|
|
||||||
def set_state(self, state, duration):
|
def set_state(self, state, duration):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
@ -418,6 +419,23 @@ class Handler:
|
||||||
for instance in harness.recording:
|
for instance in harness.recording:
|
||||||
cw.writerow(instance)
|
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):
|
class BinaryHandler(Handler):
|
||||||
def __init__(self, instance, type_str):
|
def __init__(self, instance, type_str):
|
||||||
|
@ -427,7 +445,6 @@ class BinaryHandler(Handler):
|
||||||
"""
|
"""
|
||||||
super().__init__(instance, type_str)
|
super().__init__(instance, type_str)
|
||||||
|
|
||||||
self.terminated = False
|
|
||||||
self.call_west_flash = False
|
self.call_west_flash = False
|
||||||
|
|
||||||
# Tool options
|
# Tool options
|
||||||
|
@ -447,23 +464,6 @@ class BinaryHandler(Handler):
|
||||||
except ProcessLookupError:
|
except ProcessLookupError:
|
||||||
pass
|
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):
|
def _output_reader(self, proc):
|
||||||
self.line = proc.stdout.readline()
|
self.line = proc.stdout.readline()
|
||||||
|
|
||||||
|
@ -1123,31 +1123,22 @@ class QEMUHandler(Handler):
|
||||||
# twister to judge testing result by console output
|
# twister to judge testing result by console output
|
||||||
|
|
||||||
is_timeout = True
|
is_timeout = True
|
||||||
if os.path.exists(self.pid_fn):
|
self.terminate(proc)
|
||||||
qemu_pid = int(open(self.pid_fn).read())
|
if harness.state == "passed":
|
||||||
try:
|
self.returncode = 0
|
||||||
os.kill(qemu_pid, signal.SIGKILL)
|
|
||||||
except ProcessLookupError:
|
|
||||||
pass
|
|
||||||
proc.wait()
|
|
||||||
if harness.state == "passed":
|
|
||||||
self.returncode = 0
|
|
||||||
else:
|
|
||||||
self.returncode = proc.returncode
|
|
||||||
else:
|
else:
|
||||||
proc.terminate()
|
|
||||||
proc.kill()
|
|
||||||
self.returncode = proc.returncode
|
self.returncode = proc.returncode
|
||||||
else:
|
else:
|
||||||
if os.path.exists(self.pid_fn):
|
if os.path.exists(self.pid_fn):
|
||||||
qemu_pid = int(open(self.pid_fn).read())
|
qemu_pid = int(open(self.pid_fn).read())
|
||||||
logger.debug(f"No timeout, return code from QEMU ({qemu_pid}): {proc.returncode}")
|
logger.debug(f"No timeout, return code from QEMU ({qemu_pid}): {proc.returncode}")
|
||||||
self.returncode = proc.returncode
|
self.returncode = proc.returncode
|
||||||
|
|
||||||
# Need to wait for harness to finish processing
|
# Need to wait for harness to finish processing
|
||||||
# output from QEMU. Otherwise it might miss some
|
# output from QEMU. Otherwise it might miss some
|
||||||
# error messages.
|
# 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):
|
if os.path.exists(self.pid_fn):
|
||||||
qemu_pid = int(open(self.pid_fn).read())
|
qemu_pid = int(open(self.pid_fn).read())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue