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(a)univention.de
http://www.univention.de/
Geschäftsführer: Peter H. Ganten
HRB 20755 Amtsgericht Bremen
Steuer-Nr.: 71-597-02876