diff options
| author | Richard Henderson <richard.henderson@linaro.org> | 2025-09-16 10:10:29 -0700 |
|---|---|---|
| committer | Richard Henderson <richard.henderson@linaro.org> | 2025-09-16 10:10:29 -0700 |
| commit | 41511ed734dbf32f3c42ece60db0b86e081de4d2 (patch) | |
| tree | d90bd5d4856fba8269d7b2be2f59b2aef5f718b7 /python/qemu/qmp/legacy.py | |
| parent | 5bf071485af9340fb7f387d071da0494f80e20d1 (diff) | |
| parent | 9a494d83538680651197651031375c2b6fa2490b (diff) | |
| download | focaccia-qemu-41511ed734dbf32f3c42ece60db0b86e081de4d2.tar.gz focaccia-qemu-41511ed734dbf32f3c42ece60db0b86e081de4d2.zip | |
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
Python Pull Request Python 3.14 support & synchronize with python-qemu-qmp repo # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmjJjxIACgkQfe+BBqr8 # OQ48aA/+JRRIEN8LMbNDRvPTTkvCxstSAb2q8yA+8ccWg0H+EGcewjd+oCoPOqjC # SwIMAGYJ6Dv2LW6c+rK6VjKw1Da8J9WgEpKmfoWu+1Pef8odU5PoRhAvvZdMq+Eh # Kqk0r1f87fTiZK1gCBhBUIO0oTroOYxDvIYV0B6UFDPArL8jJ5eTpGLCVAYuk8tH # MuzQD0IcxCBoraOx9vqVMbKIHwMH/m9pJ2IqINzIStpLoFgT1d5V9CoKXImMVXmF # XovcMWQzFz1a/lm0ybSAzhgXcpW/vNjstb1IcrigYjQWXU6S+/bRpq17c2WqAJtG # 78Dal7heSjpvWyyCCii+QO+BegH53Mgz3W+aQN7+fkcepjivVYy8tnxOrSjJR+pX # DqRhMNSc4CrLvJH4BOHKUsJaWMxjd4oJiNhUmhJ7MxZhPTHZvERsOo9kpoJo4eTw # GhRV98FnJbotgs2kjQpSBF8FDj9LZqPwTfMuEU2NUsIB9o7/Iqj36RDe9L+2r9Ch # 2UKhnUg58y4eYFoC4CO8yCfjsR6HzLdqiVaDhcu5pdQM0Dw1pxrSIHb6faNmSLL5 # v0brhgJGujWt6wAc2c3ASMf8qpWkBrlVfHybodOB2cUDcRgNk85M/s41PnGShqBZ # Qq7VW9zR4sejwof9dTwYKuwsNzxzFdS2nLwPPkud5aDngrLsNn0= # =jZpa # -----END PGP SIGNATURE----- # gpg: Signature made Tue 16 Sep 2025 09:23:46 AM PDT # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # 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 * tag 'python-pull-request' of https://gitlab.com/jsnow/qemu: iotests/check: always enable all python warnings iotests/151: ensure subprocesses are cleaned up iotests/147: ensure temporary sockets are closed before exiting python: ensure QEMUQtestProtocol closes its socket iotests: drop compat for old version context manager python: synchronize qemu.qmp documentation python: backport 'avoid creating additional event loops per thread' python: backport 'Remove deprecated get_event_loop calls' python: backport 'qmp-tui: Do not crash if optional dependencies are not met' python: backport 'qmp-shell-wrap: handle missing binary gracefully' python: backport 'make require() preserve async-ness' python: backport 'feat: allow setting read buffer limit' python: backport 'qmp-shell: add common_parser()' python: backport 'Use @asynciocontextmanager' python: backport 'drop Python3.6 workarounds' python: backport 'protocol: adjust logging name when changing client name' python: backport 'kick event queue on legacy event_pull()' python: backport 'EventListener: add __repr__ method' python: backport 'Change error classes to have better repr methods' Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'python/qemu/qmp/legacy.py')
| -rw-r--r-- | python/qemu/qmp/legacy.py | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index 22a2b5616e..060ed0eb9d 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -38,6 +38,7 @@ from typing import ( from .error import QMPError from .protocol import Runstate, SocketAddrT from .qmp_client import QMPClient +from .util import get_or_create_event_loop #: QMPMessage is an entire QMP message of any kind. @@ -86,10 +87,13 @@ class QEMUMonitorProtocol: "server argument should be False when passing a socket") self._qmp = QMPClient(nickname) - self._aloop = asyncio.get_event_loop() self._address = address self._timeout: Optional[float] = None + # This is a sync shim intended for use in fully synchronous + # programs. Create and set an event loop if necessary. + self._aloop = get_or_create_event_loop() + if server: assert not isinstance(self._address, socket.socket) self._sync(self._qmp.start_server(self._address)) @@ -231,6 +235,9 @@ class QEMUMonitorProtocol: :return: The first available QMP event, or None. """ + # Kick the event loop to allow events to accumulate + self._sync(asyncio.sleep(0)) + if not wait: # wait is False/0: "do not wait, do not except." if self._qmp.events.empty(): @@ -286,8 +293,8 @@ class QEMUMonitorProtocol: """ Set the timeout for QMP RPC execution. - This timeout affects the `cmd`, `cmd_obj`, and `command` methods. - The `accept`, `pull_event` and `get_event` methods have their + This timeout affects the `cmd`, `cmd_obj`, and `cmd_raw` methods. + The `accept`, `pull_event` and `get_events` methods have their own configurable timeouts. :param timeout: @@ -303,17 +310,30 @@ class QEMUMonitorProtocol: self._qmp.send_fd_scm(fd) def __del__(self) -> None: - if self._qmp.runstate == Runstate.IDLE: - return + if self._qmp.runstate != Runstate.IDLE: + self._qmp.logger.warning( + "QEMUMonitorProtocol object garbage collected without a prior " + "call to close()" + ) if not self._aloop.is_running(): - self.close() - else: - # Garbage collection ran while the event loop was running. - # Nothing we can do about it now, but if we don't raise our - # own error, the user will be treated to a lot of traceback - # they might not understand. + if self._qmp.runstate != Runstate.IDLE: + # If the user neglected to close the QMP session and we + # are not currently running in an asyncio context, we + # have the opportunity to close the QMP session. If we + # do not do this, the error messages presented over + # dangling async resources may not make any sense to the + # user. + self.close() + + if self._qmp.runstate != Runstate.IDLE: + # If QMP is still not quiesced, it means that the garbage + # collector ran from a context within the event loop and we + # are simply too late to take any corrective action. Raise + # our own error to give meaningful feedback to the user in + # order to prevent pages of asyncio stacktrace jargon. raise QMPError( - "QEMUMonitorProtocol.close()" - " was not called before object was garbage collected" + "QEMUMonitorProtocol.close() was not called before object was " + "garbage collected, and could not be closed due to GC running " + "in the event loop" ) |