mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/jsnow-gitlab/tags/python-pull-request' into staging
Pull request # gpg: Signature made Tue 20 Oct 2020 20:04:54 BST # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full] # Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB # Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E * remotes/jsnow-gitlab/tags/python-pull-request: (21 commits) python/qemu/qmp.py: Fix settimeout operation python/qemu/qmp.py: re-raise OSError when encountered python: add mypy config python/qemu/qmp.py: Preserve error context on re-raise python/qemu/console_socket.py: avoid encoding to/from string python/qemu/console_socket.py: Add type hint annotations python/qemu/console_socket.py: Clarify type of drain_thread python/qemu/console_socket.py: fix typing of settimeout python/qemu/console_socket.py: Correct type of recv() python/qemu: Add mypy type annotations iotests.py: Adjust HMP kwargs typing python/qemu: make 'args' style arguments immutable python/machine.py: fix _popen access python/machine.py: Add _qmp access shim python/machine.py: use qmp.command python/machine.py: Handle None events in events_wait python/machine.py: Don't modify state in _base_args() python/machine.py: reorder __init__ python/machine.py: Fix monitor address typing python/qemu: use isort to lay out imports ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+8
-1
@@ -2373,11 +2373,18 @@ S: Maintained
|
||||
F: include/sysemu/cryptodev*.h
|
||||
F: backends/cryptodev*.c
|
||||
|
||||
Python library
|
||||
M: John Snow <jsnow@redhat.com>
|
||||
M: Cleber Rosa <crosa@redhat.com>
|
||||
R: Eduardo Habkost <ehabkost@redhat.com>
|
||||
S: Maintained
|
||||
F: python/
|
||||
T: git https://gitlab.com/jsnow/qemu.git python
|
||||
|
||||
Python scripts
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
M: Cleber Rosa <crosa@redhat.com>
|
||||
S: Odd fixes
|
||||
F: python/qemu/*py
|
||||
F: scripts/*.py
|
||||
F: tests/*.py
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[mypy]
|
||||
strict = True
|
||||
python_version = 3.6
|
||||
warn_unused_configs = True
|
||||
@@ -0,0 +1,7 @@
|
||||
[settings]
|
||||
force_grid_wrap=4
|
||||
force_sort_within_sections=True
|
||||
include_trailing_comma=True
|
||||
line_length=72
|
||||
lines_after_imports=2
|
||||
multi_line_output=3
|
||||
@@ -17,6 +17,8 @@ accelerators.
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@@ -29,7 +31,7 @@ ADDITIONAL_ARCHES = {
|
||||
}
|
||||
|
||||
|
||||
def list_accel(qemu_bin):
|
||||
def list_accel(qemu_bin: str) -> List[str]:
|
||||
"""
|
||||
List accelerators enabled in the QEMU binary.
|
||||
|
||||
@@ -49,7 +51,8 @@ def list_accel(qemu_bin):
|
||||
return [acc.strip() for acc in out.splitlines()[1:]]
|
||||
|
||||
|
||||
def kvm_available(target_arch=None, qemu_bin=None):
|
||||
def kvm_available(target_arch: Optional[str] = None,
|
||||
qemu_bin: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Check if KVM is available using the following heuristic:
|
||||
- Kernel module is present in the host;
|
||||
@@ -72,7 +75,7 @@ def kvm_available(target_arch=None, qemu_bin=None):
|
||||
return True
|
||||
|
||||
|
||||
def tcg_available(qemu_bin):
|
||||
def tcg_available(qemu_bin: str) -> bool:
|
||||
"""
|
||||
Check if TCG is available.
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ which can drain a socket and optionally dump the bytes to file.
|
||||
# the COPYING file in the top-level directory.
|
||||
#
|
||||
|
||||
from collections import deque
|
||||
import socket
|
||||
import threading
|
||||
from collections import deque
|
||||
import time
|
||||
from typing import Deque, Optional
|
||||
|
||||
|
||||
class ConsoleSocket(socket.socket):
|
||||
@@ -29,22 +30,22 @@ class ConsoleSocket(socket.socket):
|
||||
Optionally a file path can be passed in and we will also
|
||||
dump the characters to this file for debugging purposes.
|
||||
"""
|
||||
def __init__(self, address, file=None, drain=False):
|
||||
self._recv_timeout_sec = 300
|
||||
def __init__(self, address: str, file: Optional[str] = None,
|
||||
drain: bool = False):
|
||||
self._recv_timeout_sec = 300.0
|
||||
self._sleep_time = 0.5
|
||||
self._buffer = deque()
|
||||
self._buffer: Deque[int] = deque()
|
||||
socket.socket.__init__(self, socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.connect(address)
|
||||
self._logfile = None
|
||||
if file:
|
||||
self._logfile = open(file, "w")
|
||||
self._logfile = open(file, "bw")
|
||||
self._open = True
|
||||
self._drain_thread = None
|
||||
if drain:
|
||||
self._drain_thread = self._thread_start()
|
||||
else:
|
||||
self._drain_thread = None
|
||||
|
||||
def _drain_fn(self):
|
||||
def _drain_fn(self) -> None:
|
||||
"""Drains the socket and runs while the socket is open."""
|
||||
while self._open:
|
||||
try:
|
||||
@@ -55,7 +56,7 @@ class ConsoleSocket(socket.socket):
|
||||
# self._open is set to False.
|
||||
time.sleep(self._sleep_time)
|
||||
|
||||
def _thread_start(self):
|
||||
def _thread_start(self) -> threading.Thread:
|
||||
"""Kick off a thread to drain the socket."""
|
||||
# Configure socket to not block and timeout.
|
||||
# This allows our drain thread to not block
|
||||
@@ -67,7 +68,7 @@ class ConsoleSocket(socket.socket):
|
||||
drain_thread.start()
|
||||
return drain_thread
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close the base object and wait for the thread to terminate"""
|
||||
if self._open:
|
||||
self._open = False
|
||||
@@ -79,51 +80,42 @@ class ConsoleSocket(socket.socket):
|
||||
self._logfile.close()
|
||||
self._logfile = None
|
||||
|
||||
def _drain_socket(self):
|
||||
def _drain_socket(self) -> None:
|
||||
"""process arriving characters into in memory _buffer"""
|
||||
data = socket.socket.recv(self, 1)
|
||||
# latin1 is needed since there are some chars
|
||||
# we are receiving that cannot be encoded to utf-8
|
||||
# such as 0xe2, 0x80, 0xA6.
|
||||
string = data.decode("latin1")
|
||||
if self._logfile:
|
||||
self._logfile.write("{}".format(string))
|
||||
self._logfile.write(data)
|
||||
self._logfile.flush()
|
||||
for c in string:
|
||||
self._buffer.extend(c)
|
||||
self._buffer.extend(data)
|
||||
|
||||
def recv(self, bufsize=1):
|
||||
def recv(self, bufsize: int = 1, flags: int = 0) -> bytes:
|
||||
"""Return chars from in memory buffer.
|
||||
Maintains the same API as socket.socket.recv.
|
||||
"""
|
||||
if self._drain_thread is None:
|
||||
# Not buffering the socket, pass thru to socket.
|
||||
return socket.socket.recv(self, bufsize)
|
||||
return socket.socket.recv(self, bufsize, flags)
|
||||
assert not flags, "Cannot pass flags to recv() in drained mode"
|
||||
start_time = time.time()
|
||||
while len(self._buffer) < bufsize:
|
||||
time.sleep(self._sleep_time)
|
||||
elapsed_sec = time.time() - start_time
|
||||
if elapsed_sec > self._recv_timeout_sec:
|
||||
raise socket.timeout
|
||||
chars = ''.join([self._buffer.popleft() for i in range(bufsize)])
|
||||
# We choose to use latin1 to remain consistent with
|
||||
# handle_read() and give back the same data as the user would
|
||||
# receive if they were reading directly from the
|
||||
# socket w/o our intervention.
|
||||
return chars.encode("latin1")
|
||||
return bytes((self._buffer.popleft() for i in range(bufsize)))
|
||||
|
||||
def setblocking(self, value):
|
||||
def setblocking(self, value: bool) -> None:
|
||||
"""When not draining we pass thru to the socket,
|
||||
since when draining we control socket blocking.
|
||||
"""
|
||||
if self._drain_thread is None:
|
||||
socket.socket.setblocking(self, value)
|
||||
|
||||
def settimeout(self, seconds):
|
||||
def settimeout(self, value: Optional[float]) -> None:
|
||||
"""When not draining we pass thru to the socket,
|
||||
since when draining we control the timeout.
|
||||
"""
|
||||
if seconds is not None:
|
||||
self._recv_timeout_sec = seconds
|
||||
if value is not None:
|
||||
self._recv_timeout_sec = value
|
||||
if self._drain_thread is None:
|
||||
socket.socket.settimeout(self, seconds)
|
||||
socket.socket.settimeout(self, value)
|
||||
|
||||
+187
-121
File diff suppressed because it is too large
Load Diff
+54
-35
@@ -7,21 +7,22 @@
|
||||
# This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
# the COPYING file in the top-level directory.
|
||||
|
||||
import json
|
||||
import errno
|
||||
import socket
|
||||
import json
|
||||
import logging
|
||||
import socket
|
||||
from types import TracebackType
|
||||
from typing import (
|
||||
Any,
|
||||
cast,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
TextIO,
|
||||
Type,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
from types import TracebackType
|
||||
|
||||
|
||||
# QMPMessage is a QMP Message of any kind.
|
||||
@@ -90,7 +91,9 @@ class QEMUMonitorProtocol:
|
||||
#: Logger object for debugging messages
|
||||
logger = logging.getLogger('QMP')
|
||||
|
||||
def __init__(self, address, server=False, nickname=None):
|
||||
def __init__(self, address: SocketAddrT,
|
||||
server: bool = False,
|
||||
nickname: Optional[str] = None):
|
||||
"""
|
||||
Create a QEMUMonitorProtocol class.
|
||||
|
||||
@@ -102,7 +105,7 @@ class QEMUMonitorProtocol:
|
||||
@note No connection is established, this is done by the connect() or
|
||||
accept() methods
|
||||
"""
|
||||
self.__events = []
|
||||
self.__events: List[QMPMessage] = []
|
||||
self.__address = address
|
||||
self.__sock = self.__get_sock()
|
||||
self.__sockfile: Optional[TextIO] = None
|
||||
@@ -114,14 +117,14 @@ class QEMUMonitorProtocol:
|
||||
self.__sock.bind(self.__address)
|
||||
self.__sock.listen(1)
|
||||
|
||||
def __get_sock(self):
|
||||
def __get_sock(self) -> socket.socket:
|
||||
if isinstance(self.__address, tuple):
|
||||
family = socket.AF_INET
|
||||
else:
|
||||
family = socket.AF_UNIX
|
||||
return socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
def __negotiate_capabilities(self):
|
||||
def __negotiate_capabilities(self) -> QMPMessage:
|
||||
greeting = self.__json_read()
|
||||
if greeting is None or "QMP" not in greeting:
|
||||
raise QMPConnectError
|
||||
@@ -131,7 +134,7 @@ class QEMUMonitorProtocol:
|
||||
return greeting
|
||||
raise QMPCapabilitiesError
|
||||
|
||||
def __json_read(self, only_event=False):
|
||||
def __json_read(self, only_event: bool = False) -> Optional[QMPMessage]:
|
||||
assert self.__sockfile is not None
|
||||
while True:
|
||||
data = self.__sockfile.readline()
|
||||
@@ -148,7 +151,7 @@ class QEMUMonitorProtocol:
|
||||
continue
|
||||
return resp
|
||||
|
||||
def __get_events(self, wait=False):
|
||||
def __get_events(self, wait: Union[bool, float] = False) -> None:
|
||||
"""
|
||||
Check for new events in the stream and cache them in __events.
|
||||
|
||||
@@ -161,15 +164,19 @@ class QEMUMonitorProtocol:
|
||||
retrieved or if some other error occurred.
|
||||
"""
|
||||
|
||||
# Current timeout and blocking status
|
||||
current_timeout = self.__sock.gettimeout()
|
||||
|
||||
# Check for new events regardless and pull them into the cache:
|
||||
self.__sock.setblocking(False)
|
||||
self.__sock.settimeout(0) # i.e. setblocking(False)
|
||||
try:
|
||||
self.__json_read()
|
||||
except OSError as err:
|
||||
if err.errno == errno.EAGAIN:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(True)
|
||||
# EAGAIN: No data available; not critical
|
||||
if err.errno != errno.EAGAIN:
|
||||
raise
|
||||
finally:
|
||||
self.__sock.settimeout(current_timeout)
|
||||
|
||||
# Wait for new events, if needed.
|
||||
# if wait is 0.0, this means "no wait" and is also implicitly false.
|
||||
@@ -178,15 +185,18 @@ class QEMUMonitorProtocol:
|
||||
self.__sock.settimeout(wait)
|
||||
try:
|
||||
ret = self.__json_read(only_event=True)
|
||||
except socket.timeout:
|
||||
raise QMPTimeoutError("Timeout waiting for event")
|
||||
except:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
except socket.timeout as err:
|
||||
raise QMPTimeoutError("Timeout waiting for event") from err
|
||||
except Exception as err:
|
||||
msg = "Error while reading from socket"
|
||||
raise QMPConnectError(msg) from err
|
||||
finally:
|
||||
self.__sock.settimeout(current_timeout)
|
||||
|
||||
if ret is None:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
self.__sock.settimeout(None)
|
||||
|
||||
def __enter__(self):
|
||||
def __enter__(self) -> 'QEMUMonitorProtocol':
|
||||
# Implement context manager enter function.
|
||||
return self
|
||||
|
||||
@@ -199,7 +209,7 @@ class QEMUMonitorProtocol:
|
||||
# Implement context manager exit function.
|
||||
self.close()
|
||||
|
||||
def connect(self, negotiate=True):
|
||||
def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
|
||||
"""
|
||||
Connect to the QMP Monitor and perform capabilities negotiation.
|
||||
|
||||
@@ -214,7 +224,7 @@ class QEMUMonitorProtocol:
|
||||
return self.__negotiate_capabilities()
|
||||
return None
|
||||
|
||||
def accept(self, timeout=15.0):
|
||||
def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
|
||||
"""
|
||||
Await connection from QMP Monitor and perform capabilities negotiation.
|
||||
|
||||
@@ -250,7 +260,9 @@ class QEMUMonitorProtocol:
|
||||
self.logger.debug("<<< %s", resp)
|
||||
return resp
|
||||
|
||||
def cmd(self, name, args=None, cmd_id=None):
|
||||
def cmd(self, name: str,
|
||||
args: Optional[Dict[str, Any]] = None,
|
||||
cmd_id: Optional[Any] = None) -> QMPMessage:
|
||||
"""
|
||||
Build a QMP command and send it to the QMP Monitor.
|
||||
|
||||
@@ -258,14 +270,14 @@ class QEMUMonitorProtocol:
|
||||
@param args: command arguments (dict)
|
||||
@param cmd_id: command id (dict, list, string or int)
|
||||
"""
|
||||
qmp_cmd = {'execute': name}
|
||||
qmp_cmd: QMPMessage = {'execute': name}
|
||||
if args:
|
||||
qmp_cmd['arguments'] = args
|
||||
if cmd_id:
|
||||
qmp_cmd['id'] = cmd_id
|
||||
return self.cmd_obj(qmp_cmd)
|
||||
|
||||
def command(self, cmd, **kwds):
|
||||
def command(self, cmd: str, **kwds: Any) -> QMPReturnValue:
|
||||
"""
|
||||
Build and send a QMP command to the monitor, report errors if any
|
||||
"""
|
||||
@@ -278,7 +290,8 @@ class QEMUMonitorProtocol:
|
||||
)
|
||||
return cast(QMPReturnValue, ret['return'])
|
||||
|
||||
def pull_event(self, wait=False):
|
||||
def pull_event(self,
|
||||
wait: Union[bool, float] = False) -> Optional[QMPMessage]:
|
||||
"""
|
||||
Pulls a single event.
|
||||
|
||||
@@ -298,7 +311,7 @@ class QEMUMonitorProtocol:
|
||||
return self.__events.pop(0)
|
||||
return None
|
||||
|
||||
def get_events(self, wait=False):
|
||||
def get_events(self, wait: bool = False) -> List[QMPMessage]:
|
||||
"""
|
||||
Get a list of available QMP events.
|
||||
|
||||
@@ -315,13 +328,13 @@ class QEMUMonitorProtocol:
|
||||
self.__get_events(wait)
|
||||
return self.__events
|
||||
|
||||
def clear_events(self):
|
||||
def clear_events(self) -> None:
|
||||
"""
|
||||
Clear current list of pending events.
|
||||
"""
|
||||
self.__events = []
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Close the socket and socket file.
|
||||
"""
|
||||
@@ -330,16 +343,22 @@ class QEMUMonitorProtocol:
|
||||
if self.__sockfile:
|
||||
self.__sockfile.close()
|
||||
|
||||
def settimeout(self, timeout):
|
||||
def settimeout(self, timeout: Optional[float]) -> None:
|
||||
"""
|
||||
Set the socket timeout.
|
||||
|
||||
@param timeout (float): timeout in seconds, or None.
|
||||
@param timeout (float): timeout in seconds (non-zero), or None.
|
||||
@note This is a wrap around socket.settimeout
|
||||
|
||||
@raise ValueError: if timeout was set to 0.
|
||||
"""
|
||||
if timeout == 0:
|
||||
msg = "timeout cannot be 0; this engages non-blocking mode."
|
||||
msg += " Use 'None' instead to disable timeouts."
|
||||
raise ValueError(msg)
|
||||
self.__sock.settimeout(timeout)
|
||||
|
||||
def get_sock_fd(self):
|
||||
def get_sock_fd(self) -> int:
|
||||
"""
|
||||
Get the socket file descriptor.
|
||||
|
||||
@@ -347,7 +366,7 @@ class QEMUMonitorProtocol:
|
||||
"""
|
||||
return self.__sock.fileno()
|
||||
|
||||
def is_scm_available(self):
|
||||
def is_scm_available(self) -> bool:
|
||||
"""
|
||||
Check if the socket allows for SCM_RIGHTS.
|
||||
|
||||
|
||||
+36
-19
@@ -17,11 +17,17 @@ subclass of QEMUMachine, respectively.
|
||||
# Based on qmp.py.
|
||||
#
|
||||
|
||||
import socket
|
||||
import os
|
||||
from typing import Optional, TextIO
|
||||
import socket
|
||||
from typing import (
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
TextIO,
|
||||
)
|
||||
|
||||
from .machine import QEMUMachine
|
||||
from .qmp import SocketAddrT
|
||||
|
||||
|
||||
class QEMUQtestProtocol:
|
||||
@@ -38,7 +44,8 @@ class QEMUQtestProtocol:
|
||||
No conection is estabalished by __init__(), this is done
|
||||
by the connect() or accept() methods.
|
||||
"""
|
||||
def __init__(self, address, server=False):
|
||||
def __init__(self, address: SocketAddrT,
|
||||
server: bool = False):
|
||||
self._address = address
|
||||
self._sock = self._get_sock()
|
||||
self._sockfile: Optional[TextIO] = None
|
||||
@@ -46,14 +53,14 @@ class QEMUQtestProtocol:
|
||||
self._sock.bind(self._address)
|
||||
self._sock.listen(1)
|
||||
|
||||
def _get_sock(self):
|
||||
def _get_sock(self) -> socket.socket:
|
||||
if isinstance(self._address, tuple):
|
||||
family = socket.AF_INET
|
||||
else:
|
||||
family = socket.AF_UNIX
|
||||
return socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
def connect(self):
|
||||
def connect(self) -> None:
|
||||
"""
|
||||
Connect to the qtest socket.
|
||||
|
||||
@@ -62,7 +69,7 @@ class QEMUQtestProtocol:
|
||||
self._sock.connect(self._address)
|
||||
self._sockfile = self._sock.makefile(mode='r')
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
"""
|
||||
Await connection from QEMU.
|
||||
|
||||
@@ -71,7 +78,7 @@ class QEMUQtestProtocol:
|
||||
self._sock, _ = self._sock.accept()
|
||||
self._sockfile = self._sock.makefile(mode='r')
|
||||
|
||||
def cmd(self, qtest_cmd):
|
||||
def cmd(self, qtest_cmd: str) -> str:
|
||||
"""
|
||||
Send a qtest command on the wire.
|
||||
|
||||
@@ -82,14 +89,16 @@ class QEMUQtestProtocol:
|
||||
resp = self._sockfile.readline()
|
||||
return resp
|
||||
|
||||
def close(self):
|
||||
"""Close this socket."""
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Close this socket.
|
||||
"""
|
||||
self._sock.close()
|
||||
if self._sockfile:
|
||||
self._sockfile.close()
|
||||
self._sockfile = None
|
||||
|
||||
def settimeout(self, timeout):
|
||||
def settimeout(self, timeout: Optional[float]) -> None:
|
||||
"""Set a timeout, in seconds."""
|
||||
self._sock.settimeout(timeout)
|
||||
|
||||
@@ -99,8 +108,13 @@ class QEMUQtestMachine(QEMUMachine):
|
||||
A QEMU VM, with a qtest socket available.
|
||||
"""
|
||||
|
||||
def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
|
||||
socket_scm_helper=None, sock_dir=None):
|
||||
def __init__(self,
|
||||
binary: str,
|
||||
args: Sequence[str] = (),
|
||||
name: Optional[str] = None,
|
||||
test_dir: str = "/var/tmp",
|
||||
socket_scm_helper: Optional[str] = None,
|
||||
sock_dir: Optional[str] = None):
|
||||
if name is None:
|
||||
name = "qemu-%d" % os.getpid()
|
||||
if sock_dir is None:
|
||||
@@ -108,16 +122,19 @@ class QEMUQtestMachine(QEMUMachine):
|
||||
super().__init__(binary, args, name=name, test_dir=test_dir,
|
||||
socket_scm_helper=socket_scm_helper,
|
||||
sock_dir=sock_dir)
|
||||
self._qtest = None
|
||||
self._qtest: Optional[QEMUQtestProtocol] = None
|
||||
self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock")
|
||||
|
||||
def _base_args(self):
|
||||
args = super()._base_args()
|
||||
args.extend(['-qtest', 'unix:path=' + self._qtest_path,
|
||||
'-accel', 'qtest'])
|
||||
@property
|
||||
def _base_args(self) -> List[str]:
|
||||
args = super()._base_args
|
||||
args.extend([
|
||||
'-qtest', f"unix:path={self._qtest_path}",
|
||||
'-accel', 'qtest'
|
||||
])
|
||||
return args
|
||||
|
||||
def _pre_launch(self):
|
||||
def _pre_launch(self) -> None:
|
||||
super()._pre_launch()
|
||||
self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
|
||||
|
||||
@@ -126,7 +143,7 @@ class QEMUQtestMachine(QEMUMachine):
|
||||
super()._post_launch()
|
||||
self._qtest.accept()
|
||||
|
||||
def _post_shutdown(self):
|
||||
def _post_shutdown(self) -> None:
|
||||
super()._post_shutdown()
|
||||
self._remove_if_exists(self._qtest_path)
|
||||
|
||||
|
||||
@@ -605,7 +605,7 @@ class VM(qtest.QEMUQtestMachine):
|
||||
|
||||
def hmp(self, command_line: str, use_log: bool = False) -> QMPMessage:
|
||||
cmd = 'human-monitor-command'
|
||||
kwargs = {'command-line': command_line}
|
||||
kwargs: Dict[str, Any] = {'command-line': command_line}
|
||||
if use_log:
|
||||
return self.qmp_log(cmd, **kwargs)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user