Skip to content

Commit

Permalink
QEMUMachine: add events_wait method
Browse files Browse the repository at this point in the history
Instead of event_wait which looks for a single event, add an events_wait
which can look for any number of events simultaneously. However, it
will still only return one at a time, whichever happens first.

Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 20190523170643.20794-4-jsnow@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
(cherry picked from commit f6f4b3f)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
  • Loading branch information
jnsnow authored and mdroth committed Sep 17, 2019
1 parent 94a14e6 commit c7b4a73
Showing 1 changed file with 49 additions and 20 deletions.
69 changes: 49 additions & 20 deletions python/qemu/__init__.py
Expand Up @@ -408,42 +408,71 @@ def get_qmp_events(self, wait=False):
self._qmp.clear_events()
return events

def event_wait(self, name, timeout=60.0, match=None):
@staticmethod
def event_match(event, match=None):
"""
Wait for specified timeout on named event in QMP; optionally filter
results by match.
Check if an event matches optional match criteria.
The 'match' is checked to be a recursive subset of the 'event'; skips
branch processing on match's value None
{"foo": {"bar": 1}} matches {"foo": None}
{"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
The match criteria takes the form of a matching subdict. The event is
checked to be a superset of the subdict, recursively, with matching
values whenever those values are not None.
Examples, with the subdict queries on the left:
- None matches any object.
- {"foo": None} matches {"foo": {"bar": 1}}
- {"foo": {"baz": None}} does not match {"foo": {"bar": 1}}
- {"foo": {"baz": 2}} matches {"foo": {"bar": 1, "baz": 2}}
"""
def event_match(event, match=None):
if match is None:
return True
if match is None:
return True

for key in match:
if key in event:
if isinstance(event[key], dict):
if not event_match(event[key], match[key]):
return False
elif event[key] != match[key]:
for key in match:
if key in event:
if isinstance(event[key], dict):
if not QEMUMachine.event_match(event[key], match[key]):
return False
else:
elif event[key] != match[key]:
return False
else:
return False
return True

return True
def event_wait(self, name, timeout=60.0, match=None):
"""
event_wait waits for and returns a named event from QMP with a timeout.
name: The event to wait for.
timeout: QEMUMonitorProtocol.pull_event timeout parameter.
match: Optional match criteria. See event_match for details.
"""
return self.events_wait([(name, match)], timeout)

def events_wait(self, events, timeout=60.0):
"""
events_wait waits for and returns a named event from QMP with a timeout.
events: a sequence of (name, match_criteria) tuples.
The match criteria are optional and may be None.
See event_match for details.
timeout: QEMUMonitorProtocol.pull_event timeout parameter.
"""
def _match(event):
for name, match in events:
if (event['event'] == name and
self.event_match(event, match)):
return True
return False

# Search cached events
for event in self._events:
if (event['event'] == name) and event_match(event, match):
if _match(event):
self._events.remove(event)
return event

# Poll for new events
while True:
event = self._qmp.pull_event(wait=timeout)
if (event['event'] == name) and event_match(event, match):
if _match(event):
return event
self._events.append(event)

Expand Down

0 comments on commit c7b4a73

Please sign in to comment.