From 4bad633cb9ece35138415541a0decafda613a95f Mon Sep 17 00:00:00 2001 From: Aseda Aboagye Date: Thu, 17 Dec 2015 16:55:01 -0800 Subject: ec3po: Add graceful exit. The console and interpreter are usually killed by KeyboardInterrupt whether or not it's run standalone or by servod. This commit tries to make the exit graceful by closing pipes, file descriptors, and exiting each process. BUG=chromium:570526 BRANCH=None TEST=Run ec3po standalone and hit Ctrl+C to kill it. Observe no traceback and no leftover processes. TEST=Repeat above test, but inside servod TEST=cros lint --debug util/ec3po/console.py TEST=cros lint --debug util/ec3po/interpreter.py TEST=python2 -b util/ec3po/console_interpreter.py TEST=python2 -b util/ec3po/console_interpreter.py Change-Id: Ia151b9ede8adf7f8dec6c07277f62d097c13e63e Signed-off-by: Aseda Aboagye Reviewed-on: https://chromium-review.googlesource.com/319252 Commit-Ready: Aseda Aboagye Tested-by: Aseda Aboagye Reviewed-by: Wai-Hong Tam --- util/ec3po/console.py | 63 +++++++++++++++++++++++++++-------------------- util/ec3po/interpreter.py | 43 ++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 43 deletions(-) diff --git a/util/ec3po/console.py b/util/ec3po/console.py index 962d042ff3..39278e343d 100755 --- a/util/ec3po/console.py +++ b/util/ec3po/console.py @@ -635,32 +635,42 @@ def StartLoop(console): """ console.logger.info('EC Console is being served on %s.', console.user_pty) console.logger.debug(console) - while True: - # Check to see if pipes or the console are ready for reading. - read_list = [console.master_pty, console.cmd_pipe, console.dbg_pipe] - ready_for_reading = select.select(read_list, [], [])[0] - - for obj in ready_for_reading: - if obj is console.master_pty: - console.logger.debug('Input from user') - # Convert to bytes so we can look for non-printable chars such as - # Ctrl+A, Ctrl+E, etc. - line = bytearray(os.read(console.master_pty, CONSOLE_MAX_READ)) - for i in line: - # Handle each character as it arrives. - console.HandleChar(i) - - elif obj is console.cmd_pipe: - data = console.cmd_pipe.recv() - # Write it to the user console. - console.logger.debug('|CMD|->\'%s\'', data) - os.write(console.master_pty, data) - - elif obj is console.dbg_pipe: - data = console.dbg_pipe.recv() - # Write it to the user console. - console.logger.debug('|DBG|->\'%s\'', data) - os.write(console.master_pty, data) + try: + while True: + # Check to see if pipes or the console are ready for reading. + read_list = [console.master_pty, console.cmd_pipe, console.dbg_pipe] + ready_for_reading = select.select(read_list, [], [])[0] + + for obj in ready_for_reading: + if obj is console.master_pty: + console.logger.debug('Input from user') + # Convert to bytes so we can look for non-printable chars such as + # Ctrl+A, Ctrl+E, etc. + line = bytearray(os.read(console.master_pty, CONSOLE_MAX_READ)) + for i in line: + # Handle each character as it arrives. + console.HandleChar(i) + + elif obj is console.cmd_pipe: + data = console.cmd_pipe.recv() + # Write it to the user console. + console.logger.debug('|CMD|->\'%s\'', data) + os.write(console.master_pty, data) + + elif obj is console.dbg_pipe: + data = console.dbg_pipe.recv() + # Write it to the user console. + console.logger.debug('|DBG|->\'%s\'', data) + os.write(console.master_pty, data) + + finally: + # Close pipes. + console.dbg_pipe.close() + console.cmd_pipe.close() + # Close file descriptor. + os.close(console.master_pty) + # Exit. + sys.exit(0) def main(argv): @@ -676,7 +686,6 @@ def main(argv): # Set up argument parser. parser = argparse.ArgumentParser(description=('Start interactive EC console ' 'and interpreter.')) - # TODO(aaboagye): Eventually get this from servod. parser.add_argument('ec_uart_pty', help=('The full PTY name that the EC UART' ' is present on. eg: /dev/pts/12')) diff --git a/util/ec3po/interpreter.py b/util/ec3po/interpreter.py index 31079fb908..b71607f254 100644 --- a/util/ec3po/interpreter.py +++ b/util/ec3po/interpreter.py @@ -20,6 +20,7 @@ import logging import os import Queue import select +import sys COMMAND_RETRIES = 3 # Number of attempts to retry a command. @@ -312,19 +313,29 @@ def StartLoop(interp): Args: interp: An Interpreter object that has been properly initialised. """ - while True: - readable, writeable, _ = select.select(interp.inputs, interp.outputs, []) - - for obj in readable: - # Handle any debug prints from the EC. - if obj is interp.ec_uart_pty: - interp.HandleECData() - - # Handle any commands from the user. - elif obj is interp.cmd_pipe: - interp.HandleUserData() - - for obj in writeable: - # Send a command to the EC. - if obj is interp.ec_uart_pty: - interp.SendCmdToEC() + try: + while True: + readable, writeable, _ = select.select(interp.inputs, interp.outputs, []) + + for obj in readable: + # Handle any debug prints from the EC. + if obj is interp.ec_uart_pty: + interp.HandleECData() + + # Handle any commands from the user. + elif obj is interp.cmd_pipe: + interp.HandleUserData() + + for obj in writeable: + # Send a command to the EC. + if obj is interp.ec_uart_pty: + interp.SendCmdToEC() + + finally: + # Close pipes. + interp.cmd_pipe.close() + interp.dbg_pipe.close() + # Close file descriptor. + interp.ec_uart_pty.close() + # Exit. + sys.exit(0) -- cgit v1.2.1