diff mbox series

[v2,10/16] python/machine.py: Handle None events in event_wait

Message ID 20200602214528.12107-11-jsnow@redhat.com
State New
Headers show
Series python: add mypy support to python/qemu | expand

Commit Message

John Snow June 2, 2020, 9:45 p.m. UTC
If the timeout is 0, we can get None back. Handle this explicitly.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 python/qemu/machine.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Comments

Kevin Wolf June 4, 2020, 2:20 p.m. UTC | #1
Am 02.06.2020 um 23:45 hat John Snow geschrieben:
> If the timeout is 0, we can get None back. Handle this explicitly.
> 
> Signed-off-by: John Snow <jsnow@redhat.com>

Subject line: This is events_wait(), not event_wait(). Both functions
exist.

> @@ -562,6 +564,8 @@ def _match(event):
>          # Poll for new events
>          while True:
>              event = self._qmp.pull_event(wait=timeout)
> +            if event is None:
> +                break
>              if _match(event):
>                  return event
>              self._events.append(event)

Hm... How could this ever work? I guess we just never really tested
whether timeouts actually time out?

(It's still somewhat unintuitive that receiving an unrelated event
resets the timeout, but not the problem of this series...)

Kevin
John Snow June 4, 2020, 6:48 p.m. UTC | #2
On 6/4/20 10:20 AM, Kevin Wolf wrote:
> Am 02.06.2020 um 23:45 hat John Snow geschrieben:
>> If the timeout is 0, we can get None back. Handle this explicitly.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
> 
> Subject line: This is events_wait(), not event_wait(). Both functions
> exist.
> 
>> @@ -562,6 +564,8 @@ def _match(event):
>>          # Poll for new events
>>          while True:
>>              event = self._qmp.pull_event(wait=timeout)
>> +            if event is None:
>> +                break
>>              if _match(event):
>>                  return event
>>              self._events.append(event)
> 
> Hm... How could this ever work? I guess we just never really tested
> whether timeouts actually time out?
> 

It's weirder than you think.

pull_event, when a timeout is supplied, will pass that timeout to
QEMUMonitorProtocol.__get_events, which populates the received event
queue but does not return data on the stack. If there are no events in
the queue and we are given a timeout, we will raise QMPTimeoutError if
no event appears in that timeframe.

pull_event() will only return None in the case that you don't give it a
timeout or tell it to wait.

The typing of events_wait allows us to specify a timeout of 0 here,
which is treated as no-wait down the stack, which may return None if
there was no such event ready.

Thus, break and also return None.

(I should update the docstring here.)

> (It's still somewhat unintuitive that receiving an unrelated event
> resets the timeout, but not the problem of this series...)
> 
> Kevin
> 

Yes, it's weird. It's not a timeout on this one event, it's a timeout on
event-receiving activity. In practice, it works quite well for the
iotest suite where there are often not other event drivers present. It
was a quick hack (that I introduced!) to ensure that iotests would halt
in some finite amount of time.

--js
diff mbox series

Patch

diff --git a/python/qemu/machine.py b/python/qemu/machine.py
index 2f12cebde40..a835b7550da 100644
--- a/python/qemu/machine.py
+++ b/python/qemu/machine.py
@@ -32,7 +32,7 @@ 
 from types import TracebackType
 
 from . import qmp
-from .qmp import SocketAddrT
+from .qmp import SocketAddrT, QMPMessage
 
 LOG = logging.getLogger(__name__)
 
@@ -553,6 +553,8 @@  def _match(event):
                     return True
             return False
 
+        event: Optional[QMPMessage]
+
         # Search cached events
         for event in self._events:
             if _match(event):
@@ -562,6 +564,8 @@  def _match(event):
         # Poll for new events
         while True:
             event = self._qmp.pull_event(wait=timeout)
+            if event is None:
+                break
             if _match(event):
                 return event
             self._events.append(event)