I am having an issue with using python Threads and finds it difficult to understand what is happening behind. In the program , an OpenScenario file is running on Threads just like the below code.
I am confused as where does the Thread application ends. The program is not following the scenario rules and it is exiting before completing the rules on the scenario file. So is there any methods available to debug or see what is happening or when does the thread ends?
#!/usr/bin/env python
#
# Copyright (c) 2020 Intel Corporation
#
"""
Execute an application.
"""
import os
from enum import Enum
from threading import Thread, Event
from datetime import datetime, timedelta
import pexpect # pylint: disable=import-error
class ApplicationStatus(Enum):
"""
States of an application
"""
STOPPED = 0
STARTING = 1
RUNNING = 2
SHUTTINGDOWN = 3
ERROR = 4
class ApplicationRunner(object):
"""
Execute application
"""
def __init__(self, status_updated_fct, log_fct, ready_string=""):
"""
Constructor
"""
self._app_thread = None
self._status_updated_fct = status_updated_fct
self._log_fct = log_fct
self._shutdown_requested_event = Event()
self._ready_string = ready_string
def execute(self, cmdline, env=None, cwd=None):
"""
Starts a thread to execute the application
"""
if self.is_running():
self._log_fct("Application already running!")
return False
self._shutdown_requested_event.clear()
self._app_thread = Thread(target=self.start_and_run, args=(cmdline,
env,
cwd,
self._shutdown_requested_event,
self._ready_string,
self._status_updated_fct,
self._log_fct,))
self._app_thread.start()
return True
def start_and_run(self, cmdline, env, cwd, shutdown_requested_event, ready_string, # pylint: disable=too-many-arguments
status_updated_fct, log_fct):
"""
thread function
"""
status_updated_fct(ApplicationStatus.STARTING)
try:
process = self.start_process(cmdline, log_fct, env=env, cwd=cwd)
self.run(process, shutdown_requested_event, ready_string, status_updated_fct, log_fct)
except (KeyError, pexpect.ExceptionPexpect) as e:
self._log_fct("Error while starting process: {}".format(e))
status_updated_fct(ApplicationStatus.ERROR)
def is_running(self):
"""
returns if the application is still running
"""
if self._app_thread is None:
return False
return self._app_thread.is_alive()
def shutdown(self):
"""
Shut down the application thread
"""
if not self.is_running():
return
self._log_fct("Requesting shutdown...")
self._status_updated_fct(ApplicationStatus.SHUTTINGDOWN)
self._shutdown_requested_event.set()
if self._app_thread:
self._app_thread.join()
self._log_fct("Shutdown finished.")
def start_process(self, argument_list, log_fct, env=None, cwd=None): # pylint: disable=no-self-use
"""
Starts a process.
"""
if not argument_list:
raise KeyError("No arguments given!")
if not isinstance(argument_list, str):
executable = " ".join(argument_list)
else:
executable = argument_list
log_fct("Executing: " + executable)
process = pexpect.spawn(executable, env=env, cwd=cwd, encoding='utf-8')
#process.logfile_read = sys.stdout
return process
def run(self, process, shutdown_requested_event, ready_string, status_updated_fct, log_fct): # pylint: disable=no-self-use,too-many-arguments
"""
Threaded application execution
:return:
"""
shutting_down_trigger_time = None
signaled_running = False
while True:
if shutdown_requested_event.is_set():
if shutting_down_trigger_time is None:
shutting_down_trigger_time = datetime.now()
log_fct("Shutdown requested while process is still \
running. Sending SIGHUP/SIGINT...")
process.terminate(force=False)
else:
if (datetime.now() - shutting_down_trigger_time) > timedelta(seconds=8):
log_fct("Waited 8s for application to exit. Forcing Shutdown. \
Sending SIGKILL")
process.terminate(force=True)
try:
process.expect(u".*\n", timeout=0.1)
log_fct(process.after.strip())
if not signaled_running:
if str(process.after).find(ready_string) != -1:
status_updated_fct(ApplicationStatus.RUNNING)
log_fct("Application is ready.")
signaled_running = True
except pexpect.EOF:
# application exited
log_fct(process.before.strip())
log_fct("Application exited. Exiting run loop")
break
except pexpect.TIMEOUT:
# no output received
pass
process.close()
if process.exitstatus == 0:
status_updated_fct(ApplicationStatus.STOPPED)
else:
status_updated_fct(ApplicationStatus.ERROR)