summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2018-03-06 18:42:49 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-03-19 19:21:25 -0700
commit831d2b2597af1b92d576f6fb8c52066f0695249f (patch)
tree996bdd988c82b490553415ffee9a6b4c6968e2b4
parentad275d5fb9e8526666eae9e87b2da15938738667 (diff)
downloadchrome-ec-831d2b2597af1b92d576f6fb8c52066f0695249f.tar.gz
servod: add command muxing in ec3po
This creates a second pty for pty_driver to open, to prevent the need for freezing the user pty. This also allows the user pty to fully log and print all output. BRANCH=None BUG=b:74023102,b:73310923 TEST=servod is fast now, recovery works CQ-DEPEND=CL:958127 Change-Id: Ib369a5e64838ded98719d76f8159d71a97fe08ad Signed-off-by: Nick Sanders <nsanders@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/958128 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rwxr-xr-xutil/ec3po/console.py49
-rwxr-xr-xutil/ec3po/console_unittest.py3
2 files changed, 42 insertions, 10 deletions
diff --git a/util/ec3po/console.py b/util/ec3po/console.py
index 2cc2517582..cebad3033d 100755
--- a/util/ec3po/console.py
+++ b/util/ec3po/console.py
@@ -13,6 +13,7 @@ session-persistent command history.
from __future__ import print_function
import argparse
+import ctypes
import binascii
# pylint: disable=cros-logging-import
import logging
@@ -128,13 +129,15 @@ class Console(object):
interrogations are performed with the EC or not and how often.
"""
- def __init__(self, master_pty, user_pty, cmd_pipe, dbg_pipe):
+ def __init__(self, master_pty, user_pty, interface_pty, cmd_pipe, dbg_pipe):
"""Initalises a Console object with the provided arguments.
Args:
master_pty: File descriptor to the master side of the PTY. Used for driving
output to the user and receiving user input.
user_pty: A string representing the PTY name of the served console.
+ interface_pty: A string representing the PTY name of the served command
+ interface.
cmd_pipe: A multiprocessing.Connection object which represents the console
side of the command pipe. This must be a bidirectional pipe. Console
commands and responses utilize this pipe.
@@ -146,6 +149,7 @@ class Console(object):
self.logger = interpreter.LoggerAdapter(logger, {'pty': user_pty})
self.master_pty = master_pty
self.user_pty = user_pty
+ self.interface_pty = interface_pty
self.cmd_pipe = cmd_pipe
self.dbg_pipe = dbg_pipe
self.oobm_queue = multiprocessing.Queue()
@@ -169,6 +173,7 @@ class Console(object):
string = []
string.append('master_pty: %s' % self.master_pty)
string.append('user_pty: %s' % self.user_pty)
+ string.append('interface_pty: %s' % self.interface_pty)
string.append('cmd_pipe: %s' % self.cmd_pipe)
string.append('dbg_pipe: %s' % self.dbg_pipe)
string.append('oobm_queue: %s' % self.oobm_queue)
@@ -811,27 +816,43 @@ def IsPrintable(byte):
"""
return byte >= ord(' ') and byte <= ord('~')
-
-def StartLoop(console):
+def StartLoop(console, command_active):
"""Starts the infinite loop of console processing.
Args:
console: A Console object that has been properly initialzed.
+ command_active: multiprocessing.Value indicating if servod owns
+ the console, or user owns the console. This prevents input collisions.
"""
- console.logger.info('EC Console is being served on %s.', console.user_pty)
+ console.logger.debug('Console is being served on %s.', console.user_pty)
+ console.logger.debug('Console master is on %s.', console.master_pty)
+ console.logger.debug('Command interface is being served on %s.',
+ console.interface_pty)
console.logger.debug(console)
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]
+ read_list = [console.master_pty, console.interface_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')
+ if obj is console.master_pty and not command_active.value:
# 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))
+ console.logger.debug('Input from user: %s, locked:%s',
+ str(line).strip(), command_active.value)
+ for i in line:
+ # Handle each character as it arrives.
+ console.HandleChar(i)
+
+ if obj is console.interface_pty and command_active.value:
+ # Convert to bytes so we can look for non-printable chars such as
+ # Ctrl+A, Ctrl+E, etc.
+ line = bytearray(os.read(console.interface_pty, CONSOLE_MAX_READ))
+ console.logger.debug('Input from interface: %s, locked:%s',
+ str(line).strip(), command_active.value)
for i in line:
# Handle each character as it arrives.
console.HandleChar(i)
@@ -839,8 +860,10 @@ def StartLoop(console):
elif obj is console.cmd_pipe:
data = console.cmd_pipe.recv()
# Write it to the user console.
- console.logger.debug('|CMD|->\'%s\'', data)
+ console.logger.debug('|CMD|->\'%s\'', data.strip())
os.write(console.master_pty, data)
+ if command_active.value:
+ os.write(console.interface_pty, data)
elif obj is console.dbg_pipe:
data = console.dbg_pipe.recv()
@@ -848,8 +871,11 @@ def StartLoop(console):
# Search look buffer for enhanced EC image string.
console.CheckBufferForEnhancedImage(data)
# Write it to the user console.
- console.logger.debug('|DBG|->\'%s\'', data)
+ if len(data) > 1:
+ console.logger.debug('|DBG|->\'%s\'', data.strip())
os.write(console.master_pty, data)
+ if command_active.value:
+ os.write(console.interface_pty, data)
while not console.oobm_queue.empty():
console.logger.debug('OOBM queue ready for reading.')
@@ -861,6 +887,8 @@ def StartLoop(console):
console.cmd_pipe.close()
# Close file descriptor.
os.close(console.master_pty)
+ os.close(console.interface_pty)
+ console.logger.debug('Exit ec3po console loop for %s', console.user_pty)
# Exit.
sys.exit(0)
@@ -935,7 +963,8 @@ def main(argv):
console = Console(master_pty, os.ttyname(user_pty), cmd_pipe_interactive,
dbg_pipe_interactive)
# Start serving the console.
- StartLoop(console)
+ v = multiprocessing.Value(ctypes.c_bool, False)
+ StartLoop(console, v)
if __name__ == '__main__':
diff --git a/util/ec3po/console_unittest.py b/util/ec3po/console_unittest.py
index 768417df8f..1e9dae9efd 100755
--- a/util/ec3po/console_unittest.py
+++ b/util/ec3po/console_unittest.py
@@ -240,6 +240,7 @@ class TestConsoleEditingMethods(unittest.TestCase):
# to the interpreter.
dummy_pipe_end_0, dummy_pipe_end_1 = multiprocessing.Pipe()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
+ tempfile.TemporaryFile(),
dummy_pipe_end_0, dummy_pipe_end_1)
# Console editing methods are only valid for enhanced EC images, therefore
@@ -1146,6 +1147,7 @@ class TestConsoleCompatibility(unittest.TestCase):
# Mock out the pipes.
dummy_pipe_end_0, dummy_pipe_end_1 = mock.MagicMock(), mock.MagicMock()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
+ tempfile.TemporaryFile(),
dummy_pipe_end_0, dummy_pipe_end_1)
@mock.patch('console.Console.CheckForEnhancedECImage')
@@ -1415,6 +1417,7 @@ class TestOOBMConsoleCommands(unittest.TestCase):
# Mock out the pipes.
dummy_pipe_end_0, dummy_pipe_end_1 = mock.MagicMock(), mock.MagicMock()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
+ tempfile.TemporaryFile(),
dummy_pipe_end_0, dummy_pipe_end_1)
self.console.oobm_queue = mock.MagicMock()