summaryrefslogtreecommitdiff
path: root/meta-arm/meta-arm/lib/fvp/runner.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta-arm/meta-arm/lib/fvp/runner.py')
-rw-r--r--meta-arm/meta-arm/lib/fvp/runner.py99
1 files changed, 53 insertions, 46 deletions
diff --git a/meta-arm/meta-arm/lib/fvp/runner.py b/meta-arm/meta-arm/lib/fvp/runner.py
index 28351a39ed..c52cdc1c14 100644
--- a/meta-arm/meta-arm/lib/fvp/runner.py
+++ b/meta-arm/meta-arm/lib/fvp/runner.py
@@ -1,7 +1,7 @@
-import asyncio
import re
import subprocess
import os
+import shlex
import shutil
import sys
@@ -44,50 +44,70 @@ def check_telnet():
if not bool(shutil.which("telnet")):
raise RuntimeError("Cannot find telnet, this is needed to connect to the FVP.")
+
+class ConsolePortParser:
+ def __init__(self, lines):
+ self._lines = lines
+ self._console_ports = {}
+
+ def parse_port(self, console):
+ if console in self._console_ports:
+ return self._console_ports[console]
+
+ while True:
+ try:
+ line = next(self._lines).strip().decode(errors='ignore')
+ m = re.match(r"^(\S+): Listening for serial connection on port (\d+)$", line)
+ if m:
+ matched_console = m.group(1)
+ matched_port = int(m.group(2))
+ if matched_console == console:
+ return matched_port
+ else:
+ self._console_ports[matched_console] = matched_port
+ except StopIteration:
+ # self._lines might be a growing log file
+ pass
+
+
+# This function is backported from Python 3.8. Remove it and replace call sites
+# with shlex.join once OE-core support for earlier Python versions is dropped.
+def shlex_join(split_command):
+ """Return a shell-escaped string from *split_command*."""
+ return ' '.join(shlex.quote(arg) for arg in split_command)
+
+
class FVPRunner:
def __init__(self, logger):
- self._terminal_ports = {}
- self._line_callbacks = []
self._logger = logger
self._fvp_process = None
self._telnets = []
self._pexpects = []
- def add_line_callback(self, callback):
- self._line_callbacks.append(callback)
-
- async def start(self, config, extra_args=[], terminal_choice="none"):
+ def start(self, config, extra_args=[], terminal_choice="none", stdout=subprocess.PIPE):
cli = cli_from_config(config, terminal_choice)
cli += extra_args
# Pass through environment variables needed for GUI applications, such
# as xterm, to work.
env = config['env']
- for name in ('DISPLAY', 'WAYLAND_DISPLAY'):
+ for name in ('DISPLAY', 'WAYLAND_DISPLAY', 'XAUTHORITY'):
if name in os.environ:
env[name] = os.environ[name]
- self._logger.debug(f"Constructed FVP call: {cli}")
- self._fvp_process = await asyncio.create_subprocess_exec(
- *cli,
- stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ self._logger.debug(f"Constructed FVP call: {shlex_join(cli)}")
+ self._fvp_process = subprocess.Popen(
+ cli,
+ stdin=subprocess.DEVNULL, stdout=stdout, stderr=subprocess.STDOUT,
env=env)
- def detect_terminals(line):
- m = re.match(r"^(\S+): Listening for serial connection on port (\d+)$", line)
- if m:
- terminal = m.group(1)
- port = int(m.group(2))
- self._terminal_ports[terminal] = port
- self.add_line_callback(detect_terminals)
-
- async def stop(self):
+ def stop(self):
if self._fvp_process:
self._logger.debug(f"Terminating FVP PID {self._fvp_process.pid}")
try:
self._fvp_process.terminate()
- await asyncio.wait_for(self._fvp_process.wait(), 10.0)
- except asyncio.TimeoutError:
+ self._fvp_process.wait(10.0)
+ except subprocess.TimeoutExpired:
self._logger.debug(f"Killing FVP PID {self._fvp_process.pid}")
self._fvp_process.kill()
except ProcessLookupError:
@@ -96,8 +116,8 @@ class FVPRunner:
for telnet in self._telnets:
try:
telnet.terminate()
- await asyncio.wait_for(telnet.wait(), 10.0)
- except asyncio.TimeoutError:
+ telnet.wait(10.0)
+ except subprocess.TimeoutExpired:
telnet.kill()
except ProcessLookupError:
pass
@@ -117,34 +137,21 @@ class FVPRunner:
else:
return 0
- async def run(self, until=None):
- if until and until():
- return
-
- async for line in self._fvp_process.stdout:
- line = line.strip().decode("utf-8", errors="replace")
- for callback in self._line_callbacks:
- callback(line)
- if until and until():
- return
+ def wait(self, timeout):
+ self._fvp_process.wait(timeout)
- async def _get_terminal_port(self, terminal, timeout):
- def terminal_exists():
- return terminal in self._terminal_ports
- await asyncio.wait_for(self.run(terminal_exists), timeout)
- return self._terminal_ports[terminal]
+ @property
+ def stdout(self):
+ return self._fvp_process.stdout
- async def create_telnet(self, terminal, timeout=15.0):
+ def create_telnet(self, port):
check_telnet()
- port = await self._get_terminal_port(terminal, timeout)
- telnet = await asyncio.create_subprocess_exec("telnet", "localhost", str(port), stdin=sys.stdin, stdout=sys.stdout)
+ telnet = subprocess.Popen(["telnet", "localhost", str(port)], stdin=sys.stdin, stdout=sys.stdout)
self._telnets.append(telnet)
return telnet
- async def create_pexpect(self, terminal, timeout=15.0, **kwargs):
- check_telnet()
+ def create_pexpect(self, port, **kwargs):
import pexpect
- port = await self._get_terminal_port(terminal, timeout)
instance = pexpect.spawn(f"telnet localhost {port}", **kwargs)
self._pexpects.append(instance)
return instance