pw_emu: qemu: Improve the QMP handshake handling
Reuse the request method of QmpClient to do the initial QMP
handshake.
This also fixes a bug that causes false initialization errors when
notifications are generated during the handshake.
Bug: 315516286
Change-Id: Ia3ce77ca17138a5a728fa99301c125e4c77f4a82
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/184858
Reviewed-by: Jonathon Reinhart <jrreinhart@google.com>
Commit-Queue: Octavian Purdila <tavip@google.com>
diff --git a/pw_emu/py/pw_emu/qemu.py b/pw_emu/py/pw_emu/qemu.py
index 50112cd..6cf6ff0 100644
--- a/pw_emu/py/pw_emu/qemu.py
+++ b/pw_emu/py/pw_emu/qemu.py
@@ -50,12 +50,17 @@
def __init__(self, stream: io.RawIOBase):
self._stream = stream
- json.loads(self._stream.readline())
- cmd = json.dumps({'execute': 'qmp_capabilities'})
- self._stream.write(cmd.encode('utf-8'))
- resp = json.loads(self._stream.readline().decode('ascii'))
- if not 'return' in resp:
- raise QmpError(f'qmp init failed: {resp.get("error")}')
+ # Perform the QMP "capabilities negotiation" handshake.
+ # https://wiki.qemu.org/Documentation/QMP#Capabilities_Negotiation
+ #
+ # When the QMP connection is established, QEMU first sends a greeting
+ # message with its version and capabilities. Then the client sends
+ # 'qmp_capabilities' to exit capabilities negotiation mode. The result
+ # is an empty 'return'.
+ #
+ # self.request() will consume both the initial greeting and the
+ # subsequent 'return' response.
+ self.request('qmp_capabilities')
def request(self, cmd: str, args: Optional[Dict[str, Any]] = None) -> Any:
"""Issue a command using the qmp interface.