* [PATCH v3 0/3] python/qemu/machine: fix potential hang in QMP accept @ 2023-01-11 8:00 marcandre.lureau 2023-01-11 8:00 ` [PATCH v3 1/3] python/qmp/protocol: add open_with_socket() marcandre.lureau ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: marcandre.lureau @ 2023-01-11 8:00 UTC (permalink / raw) To: qemu-devel Cc: berrange, Beraldo Leal, John Snow, Cleber Rosa, Marc-André Lureau From: Marc-André Lureau <marcandre.lureau@redhat.com> Hi, As reported earlier by Richard Henderson ("virgl avocado hang" thread), avocado tests may hang when QEMU exits before the QMP connection is established. v3: - after merge in https://gitlab.com/qemu-project/python-qemu-qmp - resend as requested by John Snow v2: - use a socketpair() for QMP (instead of async concurrent code from v1) as suggested by Daniel Berrange. - should not regress (hopefully) Marc-André Lureau (3): python/qmp/protocol: add open_with_socket() python/qmp/legacy: make QEMUMonitorProtocol accept a socket python/qemu/machine: use socketpair() for QMP by default python/qemu/machine/machine.py | 24 ++++++++++++++++-------- python/qemu/qmp/legacy.py | 18 +++++++++++++++--- python/qemu/qmp/protocol.py | 25 ++++++++++++++++++++----- 3 files changed, 51 insertions(+), 16 deletions(-) -- 2.39.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/3] python/qmp/protocol: add open_with_socket() 2023-01-11 8:00 [PATCH v3 0/3] python/qemu/machine: fix potential hang in QMP accept marcandre.lureau @ 2023-01-11 8:00 ` marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 2/3] python/qmp/legacy: make QEMUMonitorProtocol accept a socket marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default marcandre.lureau 2 siblings, 0 replies; 9+ messages in thread From: marcandre.lureau @ 2023-01-11 8:00 UTC (permalink / raw) To: qemu-devel Cc: berrange, Beraldo Leal, John Snow, Cleber Rosa, Marc-André Lureau From: Marc-André Lureau <marcandre.lureau@redhat.com> Instead of listening for incoming connections with a SocketAddr, add a new method open_with_socket() that accepts an existing socket. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- python/qemu/qmp/protocol.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py index 6ea86650ad..4710a57f91 100644 --- a/python/qemu/qmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -18,6 +18,7 @@ from enum import Enum from functools import wraps import logging +import socket from ssl import SSLContext from typing import ( Any, @@ -296,6 +297,19 @@ async def start_server_and_accept( await self.accept() assert self.runstate == Runstate.RUNNING + @upper_half + @require(Runstate.IDLE) + async def open_with_socket(self, sock: socket.socket) -> None: + """ + Start connection with given socket. + + :param sock: A socket. + + :raise StateError: When the `Runstate` is not `IDLE`. + """ + self._reader, self._writer = await asyncio.open_connection(sock=sock) + self._set_state(Runstate.CONNECTING) + @upper_half @require(Runstate.IDLE) async def start_server(self, address: SocketAddrT, @@ -343,11 +357,12 @@ async def accept(self) -> None: protocol-level failure occurs while establishing a new session, the wrapped error may also be an `QMPError`. """ - if self._accepted is None: - raise QMPError("Cannot call accept() before start_server().") - await self._session_guard( - self._do_accept(), - 'Failed to establish connection') + if not self._reader: + if self._accepted is None: + raise QMPError("Cannot call accept() before start_server().") + await self._session_guard( + self._do_accept(), + 'Failed to establish connection') await self._session_guard( self._establish_session(), 'Failed to establish session') -- 2.39.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/3] python/qmp/legacy: make QEMUMonitorProtocol accept a socket 2023-01-11 8:00 [PATCH v3 0/3] python/qemu/machine: fix potential hang in QMP accept marcandre.lureau 2023-01-11 8:00 ` [PATCH v3 1/3] python/qmp/protocol: add open_with_socket() marcandre.lureau @ 2023-01-11 8:01 ` marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default marcandre.lureau 2 siblings, 0 replies; 9+ messages in thread From: marcandre.lureau @ 2023-01-11 8:01 UTC (permalink / raw) To: qemu-devel Cc: berrange, Beraldo Leal, John Snow, Cleber Rosa, Marc-André Lureau From: Marc-André Lureau <marcandre.lureau@redhat.com> Teach QEMUMonitorProtocol to accept an exisiting socket. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- python/qemu/qmp/legacy.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index 1951754455..8b09ee7dbb 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -22,6 +22,7 @@ # import asyncio +import socket from types import TracebackType from typing import ( Any, @@ -69,22 +70,32 @@ class QEMUMonitorProtocol: :param address: QEMU address, can be either a unix socket path (string) or a tuple in the form ( address, port ) for a TCP - connection + connection or None + :param sock: a socket or None :param server: Act as the socket server. (See 'accept') :param nickname: Optional nickname used for logging. """ - def __init__(self, address: SocketAddrT, + def __init__(self, + address: Optional[SocketAddrT] = None, + sock: Optional[socket.socket] = None, server: bool = False, nickname: Optional[str] = None): + assert address or sock self._qmp = QMPClient(nickname) self._aloop = asyncio.get_event_loop() self._address = address + self._sock = sock self._timeout: Optional[float] = None if server: - self._sync(self._qmp.start_server(self._address)) + if sock: + assert self._sock is not None + self._sync(self._qmp.open_with_socket(self._sock)) + else: + assert self._address is not None + self._sync(self._qmp.start_server(self._address)) _T = TypeVar('_T') @@ -139,6 +150,7 @@ def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: :return: QMP greeting dict, or None if negotiate is false :raise ConnectError: on connection errors """ + assert self._address is not None self._qmp.await_greeting = negotiate self._qmp.negotiate = negotiate -- 2.39.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-01-11 8:00 [PATCH v3 0/3] python/qemu/machine: fix potential hang in QMP accept marcandre.lureau 2023-01-11 8:00 ` [PATCH v3 1/3] python/qmp/protocol: add open_with_socket() marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 2/3] python/qmp/legacy: make QEMUMonitorProtocol accept a socket marcandre.lureau @ 2023-01-11 8:01 ` marcandre.lureau 2023-01-17 22:36 ` John Snow 2023-03-17 19:36 ` Vladimir Sementsov-Ogievskiy 2 siblings, 2 replies; 9+ messages in thread From: marcandre.lureau @ 2023-01-11 8:01 UTC (permalink / raw) To: qemu-devel Cc: berrange, Beraldo Leal, John Snow, Cleber Rosa, Marc-André Lureau From: Marc-André Lureau <marcandre.lureau@redhat.com> When no monitor address is given, establish the QMP communication through a socketpair() (API is also supported on Windows since Python 3.5) Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- python/qemu/machine/machine.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 748a0d807c..5b2e499e68 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -158,17 +158,13 @@ def __init__(self, self._qmp_timer = qmp_timer self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir self._log_dir = log_dir - if monitor_address is not None: - self._monitor_address = monitor_address - else: - self._monitor_address = os.path.join( - self.sock_dir, f"{self._name}-monitor.sock" - ) + self._monitor_address = monitor_address self._console_log_path = console_log if self._console_log_path: @@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: args = ['-display', 'none', '-vga', 'none'] if self._qmp_set: - if isinstance(self._monitor_address, tuple): + if self._sock_pair: + fd = self._sock_pair[0].fileno() + os.set_inheritable(fd, True) + moncdev = f"socket,id=mon,fd={fd}" + elif isinstance(self._monitor_address, tuple): moncdev = "socket,id=mon,host={},port={}".format( *self._monitor_address ) @@ -337,10 +337,17 @@ def _pre_launch(self) -> None: self._remove_files.append(self._console_address) if self._qmp_set: + monitor_address = None + sock = None + if self._monitor_address is None: + self._sock_pair = socket.socketpair() + sock = self._sock_pair[1] if isinstance(self._monitor_address, str): self._remove_files.append(self._monitor_address) + monitor_address = self._monitor_address self._qmp_connection = QEMUMonitorProtocol( - self._monitor_address, + address=monitor_address, + sock=sock, server=True, nickname=self._name ) @@ -360,6 +367,7 @@ def _pre_launch(self) -> None: )) def _post_launch(self) -> None: + self._sock_pair[0].close() if self._qmp_connection: self._qmp.accept(self._qmp_timer) -- 2.39.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-01-11 8:01 ` [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default marcandre.lureau @ 2023-01-17 22:36 ` John Snow 2023-01-18 8:02 ` Marc-André Lureau 2023-03-17 19:36 ` Vladimir Sementsov-Ogievskiy 1 sibling, 1 reply; 9+ messages in thread From: John Snow @ 2023-01-17 22:36 UTC (permalink / raw) To: marcandre.lureau; +Cc: qemu-devel, berrange, Beraldo Leal, Cleber Rosa On Wed, Jan 11, 2023 at 3:01 AM <marcandre.lureau@redhat.com> wrote: > > From: Marc-André Lureau <marcandre.lureau@redhat.com> > > When no monitor address is given, establish the QMP communication through > a socketpair() (API is also supported on Windows since Python 3.5) > > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> > --- > python/qemu/machine/machine.py | 24 ++++++++++++++++-------- > 1 file changed, 16 insertions(+), 8 deletions(-) > > diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py > index 748a0d807c..5b2e499e68 100644 > --- a/python/qemu/machine/machine.py > +++ b/python/qemu/machine/machine.py > @@ -158,17 +158,13 @@ def __init__(self, > self._qmp_timer = qmp_timer > > self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" > + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None > self._temp_dir: Optional[str] = None > self._base_temp_dir = base_temp_dir > self._sock_dir = sock_dir > self._log_dir = log_dir > > - if monitor_address is not None: > - self._monitor_address = monitor_address > - else: > - self._monitor_address = os.path.join( > - self.sock_dir, f"{self._name}-monitor.sock" > - ) > + self._monitor_address = monitor_address > > self._console_log_path = console_log > if self._console_log_path: > @@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: > args = ['-display', 'none', '-vga', 'none'] > > if self._qmp_set: > - if isinstance(self._monitor_address, tuple): > + if self._sock_pair: > + fd = self._sock_pair[0].fileno() > + os.set_inheritable(fd, True) > + moncdev = f"socket,id=mon,fd={fd}" > + elif isinstance(self._monitor_address, tuple): > moncdev = "socket,id=mon,host={},port={}".format( > *self._monitor_address > ) > @@ -337,10 +337,17 @@ def _pre_launch(self) -> None: > self._remove_files.append(self._console_address) > > if self._qmp_set: > + monitor_address = None > + sock = None > + if self._monitor_address is None: > + self._sock_pair = socket.socketpair() > + sock = self._sock_pair[1] > if isinstance(self._monitor_address, str): > self._remove_files.append(self._monitor_address) > + monitor_address = self._monitor_address > self._qmp_connection = QEMUMonitorProtocol( > - self._monitor_address, > + address=monitor_address, > + sock=sock, > server=True, > nickname=self._name > ) > @@ -360,6 +367,7 @@ def _pre_launch(self) -> None: > )) > > def _post_launch(self) -> None: > + self._sock_pair[0].close() Needs an assert or an error-check here for _sock_pair to be non-None, otherwise mypy will shout. Try running "make check-dev" from qemu.git/python directory as a smoke test. > if self._qmp_connection: > self._qmp.accept(self._qmp_timer) > > -- > 2.39.0 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-01-17 22:36 ` John Snow @ 2023-01-18 8:02 ` Marc-André Lureau 2023-01-24 0:22 ` John Snow 0 siblings, 1 reply; 9+ messages in thread From: Marc-André Lureau @ 2023-01-18 8:02 UTC (permalink / raw) To: John Snow; +Cc: qemu-devel, berrange, Beraldo Leal, Cleber Rosa Hi On Wed, Jan 18, 2023 at 2:36 AM John Snow <jsnow@redhat.com> wrote: > > On Wed, Jan 11, 2023 at 3:01 AM <marcandre.lureau@redhat.com> wrote: > > > > From: Marc-André Lureau <marcandre.lureau@redhat.com> > > > > When no monitor address is given, establish the QMP communication through > > a socketpair() (API is also supported on Windows since Python 3.5) > > > > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> > > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> > > --- > > python/qemu/machine/machine.py | 24 ++++++++++++++++-------- > > 1 file changed, 16 insertions(+), 8 deletions(-) > > > > diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py > > index 748a0d807c..5b2e499e68 100644 > > --- a/python/qemu/machine/machine.py > > +++ b/python/qemu/machine/machine.py > > @@ -158,17 +158,13 @@ def __init__(self, > > self._qmp_timer = qmp_timer > > > > self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" > > + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None > > self._temp_dir: Optional[str] = None > > self._base_temp_dir = base_temp_dir > > self._sock_dir = sock_dir > > self._log_dir = log_dir > > > > - if monitor_address is not None: > > - self._monitor_address = monitor_address > > - else: > > - self._monitor_address = os.path.join( > > - self.sock_dir, f"{self._name}-monitor.sock" > > - ) > > + self._monitor_address = monitor_address > > > > self._console_log_path = console_log > > if self._console_log_path: > > @@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: > > args = ['-display', 'none', '-vga', 'none'] > > > > if self._qmp_set: > > - if isinstance(self._monitor_address, tuple): > > + if self._sock_pair: > > + fd = self._sock_pair[0].fileno() > > + os.set_inheritable(fd, True) > > + moncdev = f"socket,id=mon,fd={fd}" > > + elif isinstance(self._monitor_address, tuple): > > moncdev = "socket,id=mon,host={},port={}".format( > > *self._monitor_address > > ) > > @@ -337,10 +337,17 @@ def _pre_launch(self) -> None: > > self._remove_files.append(self._console_address) > > > > if self._qmp_set: > > + monitor_address = None > > + sock = None > > + if self._monitor_address is None: > > + self._sock_pair = socket.socketpair() > > + sock = self._sock_pair[1] > > if isinstance(self._monitor_address, str): > > self._remove_files.append(self._monitor_address) > > + monitor_address = self._monitor_address > > self._qmp_connection = QEMUMonitorProtocol( > > - self._monitor_address, > > + address=monitor_address, > > + sock=sock, > > server=True, > > nickname=self._name > > ) > > @@ -360,6 +367,7 @@ def _pre_launch(self) -> None: > > )) > > > > def _post_launch(self) -> None: > > + self._sock_pair[0].close() > > Needs an assert or an error-check here for _sock_pair to be non-None, > otherwise mypy will shout. Try running "make check-dev" from > qemu.git/python directory as a smoke test. Good catch, it should be: + if self._sock_pair: + self._sock_pair[0].close() Let me know if you want me to resend the whole series, or if you can touch it during picking. -- Marc-André Lureau ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-01-18 8:02 ` Marc-André Lureau @ 2023-01-24 0:22 ` John Snow 0 siblings, 0 replies; 9+ messages in thread From: John Snow @ 2023-01-24 0:22 UTC (permalink / raw) To: Marc-André Lureau; +Cc: qemu-devel, berrange, Beraldo Leal, Cleber Rosa On Wed, Jan 18, 2023 at 3:03 AM Marc-André Lureau <marcandre.lureau@gmail.com> wrote: > > Hi > > On Wed, Jan 18, 2023 at 2:36 AM John Snow <jsnow@redhat.com> wrote: > > > > On Wed, Jan 11, 2023 at 3:01 AM <marcandre.lureau@redhat.com> wrote: > > > > > > From: Marc-André Lureau <marcandre.lureau@redhat.com> > > > > > > When no monitor address is given, establish the QMP communication through > > > a socketpair() (API is also supported on Windows since Python 3.5) > > > > > > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> > > > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> > > > --- > > > python/qemu/machine/machine.py | 24 ++++++++++++++++-------- > > > 1 file changed, 16 insertions(+), 8 deletions(-) > > > > > > diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py > > > index 748a0d807c..5b2e499e68 100644 > > > --- a/python/qemu/machine/machine.py > > > +++ b/python/qemu/machine/machine.py > > > @@ -158,17 +158,13 @@ def __init__(self, > > > self._qmp_timer = qmp_timer > > > > > > self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" > > > + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None > > > self._temp_dir: Optional[str] = None > > > self._base_temp_dir = base_temp_dir > > > self._sock_dir = sock_dir > > > self._log_dir = log_dir > > > > > > - if monitor_address is not None: > > > - self._monitor_address = monitor_address > > > - else: > > > - self._monitor_address = os.path.join( > > > - self.sock_dir, f"{self._name}-monitor.sock" > > > - ) > > > + self._monitor_address = monitor_address > > > > > > self._console_log_path = console_log > > > if self._console_log_path: > > > @@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: > > > args = ['-display', 'none', '-vga', 'none'] > > > > > > if self._qmp_set: > > > - if isinstance(self._monitor_address, tuple): > > > + if self._sock_pair: > > > + fd = self._sock_pair[0].fileno() > > > + os.set_inheritable(fd, True) > > > + moncdev = f"socket,id=mon,fd={fd}" > > > + elif isinstance(self._monitor_address, tuple): > > > moncdev = "socket,id=mon,host={},port={}".format( > > > *self._monitor_address > > > ) > > > @@ -337,10 +337,17 @@ def _pre_launch(self) -> None: > > > self._remove_files.append(self._console_address) > > > > > > if self._qmp_set: > > > + monitor_address = None > > > + sock = None > > > + if self._monitor_address is None: > > > + self._sock_pair = socket.socketpair() > > > + sock = self._sock_pair[1] > > > if isinstance(self._monitor_address, str): > > > self._remove_files.append(self._monitor_address) > > > + monitor_address = self._monitor_address > > > self._qmp_connection = QEMUMonitorProtocol( > > > - self._monitor_address, > > > + address=monitor_address, > > > + sock=sock, > > > server=True, > > > nickname=self._name > > > ) > > > @@ -360,6 +367,7 @@ def _pre_launch(self) -> None: > > > )) > > > > > > def _post_launch(self) -> None: > > > + self._sock_pair[0].close() > > > > Needs an assert or an error-check here for _sock_pair to be non-None, > > otherwise mypy will shout. Try running "make check-dev" from > > qemu.git/python directory as a smoke test. > > Good catch, it should be: > > + if self._sock_pair: > + self._sock_pair[0].close() > > Let me know if you want me to resend the whole series, or if you can > touch it during picking. Touching it up during picking, running tests, PR soon. Thanks, --js ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-01-11 8:01 ` [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default marcandre.lureau 2023-01-17 22:36 ` John Snow @ 2023-03-17 19:36 ` Vladimir Sementsov-Ogievskiy 2023-03-20 10:56 ` Daniel P. Berrangé 1 sibling, 1 reply; 9+ messages in thread From: Vladimir Sementsov-Ogievskiy @ 2023-03-17 19:36 UTC (permalink / raw) To: marcandre.lureau, qemu-devel Cc: berrange, Beraldo Leal, John Snow, Cleber Rosa, Maksim Davydov Hi! By my investigation, this commit (bd4c0ef409140bd1be393407c04005ac077d4574) breaks long qmp output again. Simple test: $ cd python $ cat test.py #!/usr/bin/env python3 import sys from qemu.machine import QEMUMachine monitor_address = sys.argv[2] if len(sys.argv) > 2 else None vm = QEMUMachine('../build/qemu-system-x86_64', monitor_address=monitor_address) vm.launch() for x in range(int(sys.argv[1])): vm.qmp('blockdev-add', {'driver': 'null-co', 'node-name': f'x{x}'}) vm.qmp('query-named-block-nodes') vm.shutdown() ./test.py 1000 /tmp/sock - works, but if use default behavior (socketpair) we get: $ ./test.py 1000 Traceback (most recent call last): File "/home/vsementsov/work/src/qemu/master/python/./test.py", line 14, in <module> vm.qmp('query-named-block-nodes') File "/home/vsementsov/work/src/qemu/master/python/qemu/machine/machine.py", line 686, in qmp ret = self._qmp.cmd(cmd, args=qmp_args) File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 216, in cmd return self.cmd_obj(qmp_cmd) File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 190, in cmd_obj self._sync( File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 105, in _sync return self._aloop.run_until_complete( File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete return future.result() File "/usr/lib/python3.10/asyncio/tasks.py", line 408, in wait_for return await fut File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/qmp_client.py", line 547, in _raw return await self._execute(msg, assign_id=assign_id) File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/qmp_client.py", line 496, in _execute return await self._reply(exec_id) File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/qmp_client.py", line 463, in _reply raise result qemu.qmp.qmp_client.ExecInterruptedError: Disconnected Exception ignored in: <function QEMUMonitorProtocol.__del__ at 0x7f8708283eb0> Traceback (most recent call last): File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 318, in __del__ File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 289, in close File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/legacy.py", line 105, in _sync File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete File "/usr/lib/python3.10/asyncio/tasks.py", line 408, in wait_for File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 413, in disconnect File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 725, in _wait_disconnect File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 876, in _bh_loop_forever File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 914, in _bh_recv_message File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 1015, in _recv File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/qmp_client.py", line 402, in _do_recv File "/home/vsementsov/work/src/qemu/master/python/qemu/qmp/protocol.py", line 979, in _readline File "/usr/lib/python3.10/asyncio/streams.py", line 534, in readline ValueError: Separator is not found, and chunk exceed the limit ./test.py 100 - works well. On 11.01.23 11:01, marcandre.lureau@redhat.com wrote: > From: Marc-André Lureau <marcandre.lureau@redhat.com> > > When no monitor address is given, establish the QMP communication through > a socketpair() (API is also supported on Windows since Python 3.5) > > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> > --- > python/qemu/machine/machine.py | 24 ++++++++++++++++-------- > 1 file changed, 16 insertions(+), 8 deletions(-) > > diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py > index 748a0d807c..5b2e499e68 100644 > --- a/python/qemu/machine/machine.py > +++ b/python/qemu/machine/machine.py > @@ -158,17 +158,13 @@ def __init__(self, > self._qmp_timer = qmp_timer > > self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" > + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None > self._temp_dir: Optional[str] = None > self._base_temp_dir = base_temp_dir > self._sock_dir = sock_dir > self._log_dir = log_dir > > - if monitor_address is not None: > - self._monitor_address = monitor_address > - else: > - self._monitor_address = os.path.join( > - self.sock_dir, f"{self._name}-monitor.sock" > - ) > + self._monitor_address = monitor_address > > self._console_log_path = console_log > if self._console_log_path: > @@ -303,7 +299,11 @@ def _base_args(self) -> List[str]: > args = ['-display', 'none', '-vga', 'none'] > > if self._qmp_set: > - if isinstance(self._monitor_address, tuple): > + if self._sock_pair: > + fd = self._sock_pair[0].fileno() > + os.set_inheritable(fd, True) > + moncdev = f"socket,id=mon,fd={fd}" > + elif isinstance(self._monitor_address, tuple): > moncdev = "socket,id=mon,host={},port={}".format( > *self._monitor_address > ) > @@ -337,10 +337,17 @@ def _pre_launch(self) -> None: > self._remove_files.append(self._console_address) > > if self._qmp_set: > + monitor_address = None > + sock = None > + if self._monitor_address is None: > + self._sock_pair = socket.socketpair() > + sock = self._sock_pair[1] > if isinstance(self._monitor_address, str): > self._remove_files.append(self._monitor_address) > + monitor_address = self._monitor_address > self._qmp_connection = QEMUMonitorProtocol( > - self._monitor_address, > + address=monitor_address, > + sock=sock, > server=True, > nickname=self._name > ) > @@ -360,6 +367,7 @@ def _pre_launch(self) -> None: > )) > > def _post_launch(self) -> None: > + self._sock_pair[0].close() > if self._qmp_connection: > self._qmp.accept(self._qmp_timer) > -- Best regards, Vladimir ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default 2023-03-17 19:36 ` Vladimir Sementsov-Ogievskiy @ 2023-03-20 10:56 ` Daniel P. Berrangé 0 siblings, 0 replies; 9+ messages in thread From: Daniel P. Berrangé @ 2023-03-20 10:56 UTC (permalink / raw) To: Vladimir Sementsov-Ogievskiy Cc: marcandre.lureau, qemu-devel, Beraldo Leal, John Snow, Cleber Rosa, Maksim Davydov On Fri, Mar 17, 2023 at 10:36:37PM +0300, Vladimir Sementsov-Ogievskiy wrote: > Hi! > > By my investigation, this commit (bd4c0ef409140bd1be393407c04005ac077d4574) breaks long qmp output again. > > ./test.py 1000 /tmp/sock > > - works, but if use default behavior (socketpair) we get: > > $ ./test.py 1000 > Traceback (most recent call last): snip > File "/usr/lib/python3.10/asyncio/streams.py", line 534, in readline > ValueError: Separator is not found, and chunk exceed the limit After going off in the weeds I realized this message is the key bit. We failed to pass the raised recv limit to asyncio when using a pre-opened socket. Since the QMP reply was greater than 64kb asyncio raised an exception. This was a pre-existing latent bug, exposed with the patch to enable use of socketpair(). I've CC'd you on a patch to fix this. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-03-20 10:56 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-01-11 8:00 [PATCH v3 0/3] python/qemu/machine: fix potential hang in QMP accept marcandre.lureau 2023-01-11 8:00 ` [PATCH v3 1/3] python/qmp/protocol: add open_with_socket() marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 2/3] python/qmp/legacy: make QEMUMonitorProtocol accept a socket marcandre.lureau 2023-01-11 8:01 ` [PATCH v3 3/3] python/qemu/machine: use socketpair() for QMP by default marcandre.lureau 2023-01-17 22:36 ` John Snow 2023-01-18 8:02 ` Marc-André Lureau 2023-01-24 0:22 ` John Snow 2023-03-17 19:36 ` Vladimir Sementsov-Ogievskiy 2023-03-20 10:56 ` Daniel P. Berrangé
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).