[libvirt] [RFC] duplicate suspend/resume lifecycle events with QEMU

Philipp Hahn hahn at univention.de
Tue Jun 13 04:13:57 UTC 2017


Hello,

I'm using the libvirt event mechanism and noticed, that several events
are reported twice:

> $ python examples/event-test.py qemu:///session
> Using uri:qemu:///session
> myDomainEventCallback1 EVENT: Domain installer(2) Resumed Unpaused
> myDomainEventCallback2 EVENT: Domain installer(2) Resumed Unpaused
> myDomainEventCallback1 EVENT: Domain installer(2) Resumed Unpaused
> myDomainEventCallback2 EVENT: Domain installer(2) Resumed Unpaused
> myDomainEventCallback1 EVENT: Domain installer(2) Suspended Paused
> myDomainEventCallback2 EVENT: Domain installer(2) Suspended Paused
> myDomainEventCallback1 EVENT: Domain installer(2) Suspended Paused
> myDomainEventCallback2 EVENT: Domain installer(2) Suspended Paused
> myDomainEventCallback1 EVENT: Domain installer(-1) Stopped Destroyed
> myDomainEventCallback2 EVENT: Domain installer(-1) Stopped Destroyed

(the Python example program registers 2 handlers, so each event is
printed twice, but each handler gets the suspend/resume event twice itself.)
Interestingly enough it only "suspend" and "resume", but not "created"
or "destroyed".

But it isn't Python specific, virsh shows the same behaviour:

> $ virsh  event --loop --event lifecycle
> event 'lifecycle' for domain installer: Started Booted
> event 'lifecycle' for domain installer: Suspended Paused
> event 'lifecycle' for domain installer: Resumed Unpaused
> event 'lifecycle' for domain installer: Resumed Unpaused
> event 'lifecycle' for domain installer: Suspended Paused
> event 'lifecycle' for domain installer: Suspended Paused
> event 'lifecycle' for domain installer: Stopped Destroyed

After shutting down libvirtd I used `socat stdio unix-connect:...` to
connect the the qemu UNIX socket and used
  {"execute": "stop"}
and
  {"execute": "cont"}
to verify, that QEMU only send one event. So to me it looks like libvirt
is duplicating the event.


Enabling DEBUG for »log_filters="1:qemu_monitor_json"« shows noting
wrong with QEMU:

> qemuMonitorJSONCommandWithFd:286 : Send command '{"execute":"cont","id":"libvirt-9"}' for write with FD -1
> qemuMonitorSend:972 : QEMU_MONITOR_SEND_MSG: mon=0x7f1940000910 msg={"execute":"cont","id":"libvirt-9"}
>  fd=-1
> qemuMonitorIOWrite:503 : QEMU_MONITOR_IO_WRITE: mon=0x7f1940000910 buf={"execute":"cont","id":"libvirt-9"}
>  len=37 ret=37 errno=11
> qemuMonitorIOProcess:399 : QEMU_MONITOR_IO_PROCESS: mon=0x7f1940000910 buf={"timestamp": {"seconds": 1497326279, "microseconds": 688619}, "event": "RESUME"}
> {"return": {}, "id": "libvirt-9"}
>  len=118
> qemuMonitorJSONIOProcessLine:179 : Line [{"timestamp": {"seconds": 1497326279, "microseconds": 688619}, "event": "RESUME"}]
> qemuMonitorJSONIOProcessLine:194 : QEMU_MONITOR_RECV_EVENT: mon=0x7f1940000910 event={"timestamp": {"seconds": 1497326279, "microseconds": 688619}, "event": "RESUME"}
> qemuMonitorJSONIOProcessEvent:138 : mon=0x7f1940000910 obj=0x5636fa1f1f00
> qemuMonitorEmitEvent:1186 : mon=0x7f1940000910 event=RESUME
> qemuMonitorJSONIOProcessEvent:165 : handle RESUME handler=0x7f19535903d0 data=(nil)
> qemuMonitorEmitResume:1237 : mon=0x7f1940000910


Looking at src/qemu/qemu_monitor_json.c:qemuMonitorJSONIOProcessEvent:

>  141 qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
>  142                               virJSONValuePtr obj)
>  143 {
...
>  170     qemuMonitorEmitEvent(mon, type, seconds, micros, details);

This seems to send the first event

>  171     VIR_FREE(details);
>  172
>  173     handler = bsearch(type, eventHandlers, ARRAY_CARDINALITY(eventHandlers),
>  174                       sizeof(eventHandlers[0]), qemuMonitorEventCompare);
>  175     if (handler) {
>  176         VIR_DEBUG("handle %s handler=%p data=%p", type,
>  177                   handler->handler, data);
>  178         (handler->handler)(mon, data);

and this the second instance.

>  179     }
>  180     return 0;
>  181 }

Looking deeper into the GIT source code I see this:

>   98 static qemuEventHandler eventHandlers[] = {
...
> 113     { "RESUME", qemuMonitorJSONHandleResume, },

> 544 static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
> 546     qemuMonitorEmitResume(mon);
...
> 1267 qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event,                                                                                                                                                                 
> 1268                      long long seconds, unsigned int micros,
> 1269                      const char *details)
...
> 1274     QEMU_MONITOR_CALLBACK(mon, ret, domainEvent, mon->vm, event, seconds,
> 1275                           micros, details);
...
> 1325 qemuMonitorEmitResume(qemuMonitorPtr mon)
> 1330     QEMU_MONITOR_CALLBACK(mon, ret, domainResume, mon->vm);

but this doesn't yet completely explain, why only some events are
reported twice.

Is there some way to get rid of the duplication (in Python) or at least
to distinguish them, so I can ignore the second one?


I've observed this behaviour with both Debian-Jessie

> Compiled against library: libvirt 1.2.9
> Using library: libvirt 1.2.9
> Using API: QEMU 1.2.9
> Running hypervisor: QEMU 2.6.0

and also with the newer Debian-Sid

> Compiled against library: libvirt 3.0.0
> Using library: libvirt 3.0.0
> Using API: QEMU 3.0.0
> Running hypervisor: QEMU 2.8.1

Thank you in advance.

Philipp
-- 
Philipp Hahn
Open Source Software Engineer

Univention GmbH
be open.
Mary-Somerville-Str. 1
D-28359 Bremen
Tel.: +49 421 22232-0
Fax : +49 421 22232-99
hahn at univention.de

http://www.univention.de/
Geschäftsführer: Peter H. Ganten
HRB 20755 Amtsgericht Bremen
Steuer-Nr.: 71-597-02876




More information about the libvir-list mailing list