[[RFC] 4/8] Events: Allow monitor to "enqueue" events to a queue. Also introduce a framework of handlers for each event type, that can be called when the handler is running an event.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Prerna Saxena <saxenap.ltc@xxxxxxxxx>
---
 src/qemu/qemu_event.c        |  11 +
 src/qemu/qemu_event.h        |   8 +
 src/qemu/qemu_monitor.c      | 592 +++++++++++++++++++++++++++-----
 src/qemu/qemu_monitor.h      |  80 +++--
 src/qemu/qemu_monitor_json.c | 291 ++++++++++------
 src/qemu/qemu_process.c      | 789 +++++++++++++++++++++++++++----------------
 src/qemu/qemu_process.h      |   2 +
 tests/qemumonitortestutils.c |   2 +-
 8 files changed, 1273 insertions(+), 502 deletions(-)

diff --git a/src/qemu/qemu_event.c b/src/qemu/qemu_event.c
index d52fad2..beb309f 100644
--- a/src/qemu/qemu_event.c
+++ b/src/qemu/qemu_event.c
@@ -50,6 +50,7 @@ VIR_ENUM_IMPL(qemuMonitorEvent,
               "RTC Change", "Shutdown", "Stop",
               "Suspend", "Suspend To Disk",
               "Virtual Serial Port Change",
+              "Spice migrated",
               "Wakeup", "Watchdog");
 
 virQemuEventList* virQemuEventListInit(void)
@@ -302,3 +303,13 @@ void virDomainConsumeVMEvents(virDomainObjPtr vm, void *opaque)
     }
     return;
 }
+
+extern void qemuProcessEmitMonitorEvent(qemuEventPtr ev, void *opaque);
+
+void virEventRunHandler(qemuEventPtr ev, void *opaque)
+{
+    if (!ev)
+        return;
+
+    return qemuProcessEmitMonitorEvent(ev, opaque);
+}
diff --git a/src/qemu/qemu_event.h b/src/qemu/qemu_event.h
index 4173834..8552fd1 100644
--- a/src/qemu/qemu_event.h
+++ b/src/qemu/qemu_event.h
@@ -51,6 +51,7 @@ typedef enum {
     QEMU_EVENT_SUSPEND,
     QEMU_EVENT_SUSPEND_DISK,
     QEMU_EVENT_SERIAL_CHANGE,
+    QEMU_EVENT_SPICE_MIGRATED,
     QEMU_EVENT_WAKEUP,
     QEMU_EVENT_WATCHDOG,
 
@@ -102,7 +103,12 @@ struct qemuEventTrayChangeData {
     int reason;
 };
 
+struct qemuEventShutdownData {
+    virTristateBool guest_initiated;
+};
+
 struct qemuEventGuestPanicData {
+    void *info;
 };
 
 struct qemuEventMigrationStatusData {
@@ -159,6 +165,7 @@ struct _qemuEvent {
         struct qemuEventBlockThresholdData ev_threshold;
         struct qemuEventDeviceDeletedData ev_deviceDel;
         struct qemuEventTrayChangeData ev_tray;
+        struct qemuEventShutdownData ev_shutdown;
         struct qemuEventGuestPanicData ev_panic;
         struct qemuEventMigrationStatusData ev_migStatus;
         struct qemuEventMigrationPassData ev_migPass;
@@ -219,5 +226,6 @@ int virQemuVmEventListInit(virDomainObjPtr vm);
 int virEnqueueVMEvent(virQemuEventList *qlist, qemuEventPtr ev);
 qemuEventPtr virDequeueVMEvent(virQemuEventList *qlist, virDomainObjPtr vm);
 void virEventWorkerScanQueue(void *dummy, void *opaque);
+void virEventRunHandler(qemuEventPtr ev, void *opaque);
 void virDomainConsumeVMEvents(virDomainObjPtr vm, void *opaque);
 #endif
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 7a26785..4e45cf9 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -34,6 +34,7 @@
 #include "qemu_monitor_json.h"
 #include "qemu_domain.h"
 #include "qemu_process.h"
+#include "qemu_event.h"
 #include "virerror.h"
 #include "viralloc.h"
 #include "virlog.h"
@@ -1316,6 +1317,14 @@ qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
     return ret;
 }
 
+static int
+qemuMonitorEnqueueEvent(qemuMonitorPtr mon, qemuEventPtr ev)
+{
+    int ret = -1;
+    QEMU_MONITOR_CALLBACK(mon, ret, domainEnqueueEvent, ev->vm, ev);
+
+    return ret;
+}
 
 int
 qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event,
@@ -1332,90 +1341,189 @@ qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event,
 
 
 int
-qemuMonitorEmitShutdown(qemuMonitorPtr mon, virTristateBool guest)
+qemuMonitorEmitShutdown(qemuMonitorPtr mon, virTristateBool guest,
+                        long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p guest=%u", mon, guest);
     mon->willhangup = 1;
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_SHUTDOWN;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_shutdown.guest_initiated = guest;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainShutdown, mon->vm, guest);
+    VIR_DEBUG("Vm %s received shutdown event initiated by %u",
+                                            mon->vm->def->name, guest);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitReset(qemuMonitorPtr mon)
+qemuMonitorEmitReset(qemuMonitorPtr mon, long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_RESET;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainReset, mon->vm);
+    VIR_DEBUG("Vm %s received reset event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitPowerdown(qemuMonitorPtr mon)
+qemuMonitorEmitPowerdown(qemuMonitorPtr mon, long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_POWERDOWN;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainPowerdown, mon->vm);
+    VIR_DEBUG("Vm %s received powerdown event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitStop(qemuMonitorPtr mon)
+qemuMonitorEmitStop(qemuMonitorPtr mon, long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_STOP;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainStop, mon->vm);
+    VIR_DEBUG("Vm %s received stop event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitResume(qemuMonitorPtr mon)
+qemuMonitorEmitResume(qemuMonitorPtr mon, long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_RESUME;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainResume, mon->vm);
+    VIR_DEBUG("Vm %s received resume event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitGuestPanic(qemuMonitorPtr mon,
-                          qemuMonitorEventPanicInfoPtr info)
+                          qemuMonitorEventPanicInfoPtr info,
+                          long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
-    QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm, info);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_GUEST_PANICKED;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_panic.info = info;
+
+    VIR_DEBUG("Vm %s received guest panic event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset)
+qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset,
+                         long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainRTCChange, mon->vm, offset);
+    ev->ev_type = QEMU_EVENT_RTC_CHANGE;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_rtc.offset = offset;
+
+    VIR_DEBUG("Vm %s received RTC change event", mon->vm->def->name);
+
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action)
+qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action,
+                        long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_WATCHDOG;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_watchdog.action = action;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainWatchdog, mon->vm, action);
+    VIR_DEBUG("Vm %s received watchdog event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
@@ -1424,13 +1532,39 @@ int
 qemuMonitorEmitIOError(qemuMonitorPtr mon,
                        const char *diskAlias,
                        int action,
-                       const char *reason)
+                       const char *reason,
+                       long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventIOErrorData *d = NULL;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_BLOCK_IO_ERROR;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_IOErr);
+    d->action = action;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainIOError, mon->vm,
-                          diskAlias, action, reason);
+    if (VIR_STRDUP(d->device, diskAlias) < 0) {
+        goto cleanup;
+    }
+    if (VIR_STRDUP(d->reason, reason) < 0) {
+        goto cleanup;
+    }
+    VIR_DEBUG("Vm %s received block IO error event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
+    return ret
+;
+cleanup:
+    if (d->device)
+        VIR_FREE(d->device);
+    VIR_FREE(ev);
     return ret;
 }
 
@@ -1446,15 +1580,73 @@ qemuMonitorEmitGraphics(qemuMonitorPtr mon,
                         const char *remoteService,
                         const char *authScheme,
                         const char *x509dname,
-                        const char *saslUsername)
+                        const char *saslUsername,
+                        long long seconds, unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventGraphicsData *d;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_GRAPHICS;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_graphics);
+
+    d->phase = phase;
+    d->localFamilyID = localFamily;
+    d->remoteFamilyID = remoteFamily;
+
+    if (VIR_STRDUP((d->localNode), localNode) < 0) {
+        goto cleanup;
+    }
+
+    if (VIR_STRDUP((d->localService), localService) < 0) {
+        goto cleanup;
+    }
+
+    if (VIR_STRDUP((d->remoteNode), remoteNode) < 0) {
+        goto cleanup;
+    }
+
+    if (VIR_STRDUP((d->remoteService), remoteService) < 0) {
+        goto cleanup;
+    }
+
+    if (VIR_STRDUP((d->authScheme), authScheme) < 0) {
+        goto cleanup;
+    }
+
+    if (VIR_STRDUP((d->x509dname), x509dname) < 0) {
+        goto cleanup;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainGraphics, mon->vm, phase,
-                          localFamily, localNode, localService,
-                          remoteFamily, remoteNode, remoteService,
-                          authScheme, x509dname, saslUsername);
+    if (VIR_STRDUP((d->saslUsername), saslUsername) < 0) {
+        goto cleanup;
+    }
+
+    VIR_DEBUG("Vm %s received Graphics event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    return ret;
+
+cleanup:
+    if (d->localNode)
+        VIR_FREE(d->localNode);
+    if (d->localService)
+        VIR_FREE(d->localService);
+    if (d->remoteNode)
+        VIR_FREE(d->remoteNode);
+    if (d->remoteService)
+        VIR_FREE(d->remoteService);
+    if (d->authScheme)
+        VIR_FREE(d->authScheme);
+    if (d->x509dname)
+        VIR_FREE(d->x509dname);
+    VIR_FREE(ev);
     return ret;
 }
 
@@ -1462,50 +1654,101 @@ qemuMonitorEmitGraphics(qemuMonitorPtr mon,
 int
 qemuMonitorEmitTrayChange(qemuMonitorPtr mon,
                           const char *devAlias,
-                          int reason)
+                          int reason,
+                          long long seconds,
+                          unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventTrayChangeData *d;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainTrayChange, mon->vm,
-                          devAlias, reason);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
+    ev->ev_type = QEMU_EVENT_DEVICE_TRAY_MOVED;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_tray);
+
+    if (VIR_STRDUP((d->devAlias), devAlias) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
+    d->reason = reason;
+    VIR_DEBUG("Vm %s received tray change event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitPMWakeup(qemuMonitorPtr mon)
+qemuMonitorEmitPMWakeup(qemuMonitorPtr mon, long long seconds,
+                                            unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainPMWakeup, mon->vm);
+    ev->ev_type = QEMU_EVENT_WAKEUP;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
+    VIR_DEBUG("Vm %s received PM Wakeup event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitPMSuspend(qemuMonitorPtr mon)
+qemuMonitorEmitPMSuspend(qemuMonitorPtr mon, long long seconds,
+                                             unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainPMSuspend, mon->vm);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
+    ev->ev_type = QEMU_EVENT_SUSPEND;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+
+    VIR_DEBUG("Vm %s received PM Suspend event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon)
+qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon, long long seconds,
+                                                 unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainPMSuspendDisk, mon->vm);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_SUSPEND_DISK;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
+    VIR_DEBUG("Vm %s received PM Suspend Disk event", mon->vm->def->name); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
@@ -1514,51 +1757,122 @@ int
 qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
                         const char *diskAlias,
                         int type,
-                        int status)
+                        int status, long long seconds,
+                        unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventBlockJobData *d = NULL;
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_BLOCK_JOB;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_blockJob);
+
+    if (VIR_STRDUP(d->device, diskAlias) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainBlockJob, mon->vm,
-                          diskAlias, type, status);
+    d->type = type;
+    d->status = status;
+    VIR_DEBUG("Vm %s received Block Job event", mon->vm->def->name); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
-                             unsigned long long actual)
+                             unsigned long long actual,
+                             long long seconds,
+                             unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_BALLOON_CHANGE;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_balloon.actual = actual;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainBalloonChange, mon->vm, actual);
+    VIR_DEBUG("Vm %s received balloon change event", mon->vm->def->name); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
-                             const char *devAlias)
+                             const char *devAlias,
+                             long long seconds,
+                             unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventDeviceDeletedData *d = NULL;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainDeviceDeleted, mon->vm, devAlias);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
+    ev->ev_type = QEMU_EVENT_DEVICE_DELETED;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_deviceDel);
+
+    if (VIR_STRDUP(d->device, devAlias) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
+    VIR_DEBUG("Vm %s received device deleted event for %s", mon->vm->def->name,
+                                                                     devAlias); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
-                                  const char *devAlias)
+                                  const char *devAlias,
+                                  long long seconds,
+                                  unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+    struct qemuEventNicRxFilterChangeData *d = NULL;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainNicRxFilterChanged, mon->vm, devAlias);
+    ev->ev_type = QEMU_EVENT_NIC_RX_FILTER_CHANGED;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_nic);
 
+    if (VIR_STRDUP(d->devAlias, devAlias) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
+    VIR_DEBUG("Vm %s received nic RX filter change event for %s", mon->vm->def->name,
+                                                                     devAlias); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
@@ -1566,52 +1880,110 @@ qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
 int
 qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
                             const char *devAlias,
-                            bool connected)
+                            bool connected,
+                            long long seconds,
+                            unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p, devAlias='%s', connected=%d", mon, devAlias, connected);
+    qemuEventPtr ev;
+    struct qemuEventSerialChangeData *d = NULL;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainSerialChange, mon->vm, devAlias, connected);
+    ev->ev_type = QEMU_EVENT_SERIAL_CHANGE;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    d = &(ev->evData.ev_serial);
+    d->connected = connected;
 
+    if (VIR_STRDUP(d->devAlias, devAlias) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
+    VIR_DEBUG("Vm %s received Serial change event for %s", mon->vm->def->name,
+                                                                     devAlias); 
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
-qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon)
+qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon, long long seconds,
+                             unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p", mon);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainSpiceMigrated, mon->vm);
+    ev->ev_type = QEMU_EVENT_SPICE_MIGRATED;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
 
+    VIR_DEBUG("Vm %s received spice migrated event", mon->vm->def->name);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon,
-                               int status)
+                               int status,
+                               long long seconds,
+                               unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p, status=%s",
-              mon, NULLSTR(qemuMonitorMigrationStatusTypeToString(status)));
+    qemuEventPtr ev;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainMigrationStatus, mon->vm, status);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
+    ev->ev_type = QEMU_EVENT_MIGRATION;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_migStatus.status = status;
+
+    VIR_DEBUG("Vm %s received migration status %s", mon->vm->def->name,
+               NULLSTR(qemuMonitorMigrationStatusTypeToString(status)));
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
 
 int
 qemuMonitorEmitMigrationPass(qemuMonitorPtr mon,
-                             int pass)
+                             int pass,
+                             long long seconds,
+                             unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p, pass=%d", mon, pass);
+    qemuEventPtr ev;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainMigrationPass, mon->vm, pass);
+    ev->ev_type = QEMU_EVENT_MIGRATION_PASS;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_migPass.pass = pass;
 
+    VIR_DEBUG("Vm %s received migration pass %d", mon->vm->def->name,
+                                                  pass);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
@@ -1622,15 +1994,49 @@ qemuMonitorEmitAcpiOstInfo(qemuMonitorPtr mon,
                            const char *slotType,
                            const char *slot,
                            unsigned int source,
-                           unsigned int status)
+                           unsigned int status,
+                           long long seconds,
+                           unsigned int micros)
 {
     int ret = -1;
-    VIR_DEBUG("mon=%p, alias='%s', slotType='%s', slot='%s', source='%u' status=%u",
-              mon, NULLSTR(alias), slotType, slot, source, status);
+    qemuEventPtr ev;
+    struct qemuEventAcpiOstInfoData *d = NULL;
+
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_ACPI_OST;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_acpi.source = source;
+    ev->evData.ev_acpi.status = status;
+
+    d = &(ev->evData.ev_acpi);
+
+    if (VIR_STRDUP(d->alias, alias) < 0) {
+        goto cleanup;
+    }
+    if (VIR_STRDUP(d->slotType, slotType) < 0) {
+        goto cleanup;
+    }
+    if (VIR_STRDUP(d->slot, slot) < 0) {
+        goto cleanup;
+    }
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainAcpiOstInfo, mon->vm,
-                          alias, slotType, slot, source, status);
+    VIR_DEBUG("Vm %s received ACPI OST event: alias[%s] slotType [%s] slot[%s]"
+              " status[%d]", mon->vm->def->name, alias, slotType, slot, status);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
+    return ret;
 
+cleanup:
+    if (d->alias)
+        VIR_FREE(d->alias);
+    if (d->slotType)
+        VIR_FREE(d->slotType);
+    VIR_FREE(ev);
     return ret;
 }
 
@@ -1639,16 +2045,36 @@ int
 qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon,
                               const char *nodename,
                               unsigned long long threshold,
-                              unsigned long long excess)
+                              unsigned long long excess,
+                              long long seconds,
+                              unsigned int micros)
 {
     int ret = -1;
+    qemuEventPtr ev;
+    struct qemuEventBlockThresholdData *d = NULL;
 
-    VIR_DEBUG("mon=%p, node-name='%s', threshold='%llu', excess='%llu'",
-              mon, nodename, threshold, excess);
+    if (VIR_ALLOC(ev) < 0){
+        return ret;
+    }
+
+    ev->ev_type = QEMU_EVENT_BLOCK_WRITE_THRESHOLD;
+    ev->vm = mon->vm;
+    ev->seconds = seconds;
+    ev->micros = micros;
+    ev->evData.ev_threshold.threshold = threshold;
+    ev->evData.ev_threshold.excess = excess;
 
-    QEMU_MONITOR_CALLBACK(mon, ret, domainBlockThreshold, mon->vm,
-                          nodename, threshold, excess);
+    d = &(ev->evData.ev_threshold);
 
+    if (VIR_STRDUP(d->nodename, nodename) < 0) {
+        VIR_FREE(ev);
+        return ret;
+    }
+    VIR_DEBUG("Vm %s received Block Threshold event:"
+              "node-name='%s', threshold='%llu', excess='%llu'",
+              mon->vm->def->name, nodename, threshold, excess);
+    virObjectRef(ev->vm);
+    ret = qemuMonitorEnqueueEvent(mon, ev);
     return ret;
 }
 
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index d9c27ac..7b5a984 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -35,6 +35,7 @@
 # include "device_conf.h"
 # include "cpu/cpu.h"
 # include "util/virgic.h"
+# include "qemu_event.h"
 
 typedef struct _qemuMonitor qemuMonitor;
 typedef qemuMonitor *qemuMonitorPtr;
@@ -89,7 +90,7 @@ struct _qemuMonitorEventPanicInfoHyperv {
 };
 
 typedef struct _qemuMonitorEventPanicInfo qemuMonitorEventPanicInfo;
-typedef qemuMonitorEventPanicInfo *qemuMonitorEventPanicInfoPtr;
+typedef qemuMonitorEventPanicInfo * qemuMonitorEventPanicInfoPtr;
 struct _qemuMonitorEventPanicInfo {
     qemuMonitorEventPanicInfoType type;
     union {
@@ -128,6 +129,10 @@ typedef int (*qemuMonitorDomainEventCallback)(qemuMonitorPtr mon,
                                               unsigned int micros,
                                               const char *details,
                                               void *opaque);
+typedef int (*qemuMonitorDomainEnqueueEventCallback)(qemuMonitorPtr mon,
+                                              virDomainObjPtr vm,
+                                              qemuEventPtr ev,
+                                              void *opaque);
 typedef int (*qemuMonitorDomainShutdownCallback)(qemuMonitorPtr mon,
                                                  virDomainObjPtr vm,
                                                  virTristateBool guest,
@@ -254,6 +259,7 @@ struct _qemuMonitorCallbacks {
     qemuMonitorErrorNotifyCallback errorNotify;
     qemuMonitorDiskSecretLookupCallback diskSecretLookup;
     qemuMonitorDomainEventCallback domainEvent;
+    qemuMonitorDomainEnqueueEventCallback domainEnqueueEvent;
     qemuMonitorDomainShutdownCallback domainShutdown;
     qemuMonitorDomainResetCallback domainReset;
     qemuMonitorDomainPowerdownCallback domainPowerdown;
@@ -345,17 +351,25 @@ int qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
 int qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event,
                          long long seconds, unsigned int micros,
                          const char *details);
-int qemuMonitorEmitShutdown(qemuMonitorPtr mon, virTristateBool guest);
-int qemuMonitorEmitReset(qemuMonitorPtr mon);
-int qemuMonitorEmitPowerdown(qemuMonitorPtr mon);
-int qemuMonitorEmitStop(qemuMonitorPtr mon);
-int qemuMonitorEmitResume(qemuMonitorPtr mon);
-int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset);
-int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action);
+int qemuMonitorEmitShutdown(qemuMonitorPtr mon, virTristateBool guest,
+                            long long seconds, unsigned int micros);
+int qemuMonitorEmitReset(qemuMonitorPtr mon,
+                         long long seconds, unsigned int micros);
+int qemuMonitorEmitPowerdown(qemuMonitorPtr mon,
+                             long long seconds, unsigned int micros);
+int qemuMonitorEmitStop(qemuMonitorPtr mon,
+                        long long seconds, unsigned int micros);
+int qemuMonitorEmitResume(qemuMonitorPtr mon,
+                          long long seconds, unsigned int micros);
+int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset,
+                             long long seconds, unsigned int micros);
+int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action,
+                            long long seconds, unsigned int micros);
 int qemuMonitorEmitIOError(qemuMonitorPtr mon,
                            const char *diskAlias,
                            int action,
-                           const char *reason);
+                           const char *reason,
+                           long long seconds, unsigned int micros);
 int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
                             int phase,
                             int localFamily,
@@ -366,45 +380,61 @@ int qemuMonitorEmitGraphics(qemuMonitorPtr mon,
                             const char *remoteService,
                             const char *authScheme,
                             const char *x509dname,
-                            const char *saslUsername);
+                            const char *saslUsername,
+                            long long seconds, unsigned int micros);
 int qemuMonitorEmitTrayChange(qemuMonitorPtr mon,
                               const char *devAlias,
-                              int reason);
-int qemuMonitorEmitPMWakeup(qemuMonitorPtr mon);
-int qemuMonitorEmitPMSuspend(qemuMonitorPtr mon);
+                              int reason,
+                              long long seconds, unsigned int micros);
+int qemuMonitorEmitPMWakeup(qemuMonitorPtr mon,
+                            long long seconds, unsigned int micros);
+int qemuMonitorEmitPMSuspend(qemuMonitorPtr mon,
+                             long long seconds, unsigned int micros);
 int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
                             const char *diskAlias,
                             int type,
-                            int status);
+                            int status,
+                            long long seconds, unsigned int micros);
 int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
-                                 unsigned long long actual);
-int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
+                                 unsigned long long actual,
+                                 long long seconds, unsigned int micros);
+int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon,
+                                 long long seconds, unsigned int micros);
 int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon,
-                              qemuMonitorEventPanicInfoPtr info);
+                              qemuMonitorEventPanicInfoPtr info,
+                              long long seconds, unsigned int micros);
 int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
-                                 const char *devAlias);
+                                 const char *devAlias,
+                                 long long seconds, unsigned int micros);
 int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
-                                      const char *devAlias);
+                                      const char *devAlias,
+                                      long long seconds, unsigned int micros);
 int qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
                                 const char *devAlias,
-                                bool connected);
-int qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon);
+                                bool connected,
+                                long long seconds, unsigned int micros);
+int qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon,
+                                 long long seconds, unsigned int micros);
 int qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon,
-                                   int status);
+                                   int status,
+                                   long long seconds, unsigned int micros);
 int qemuMonitorEmitMigrationPass(qemuMonitorPtr mon,
-                                 int pass);
+                                 int pass,
+                                 long long seconds, unsigned int micros);
 
 int qemuMonitorEmitAcpiOstInfo(qemuMonitorPtr mon,
                                const char *alias,
                                const char *slotType,
                                const char *slot,
                                unsigned int source,
-                               unsigned int status);
+                               unsigned int status,
+                               long long seconds, unsigned int micros);
 
 int qemuMonitorEmitBlockThreshold(qemuMonitorPtr mon,
                                   const char *nodename,
                                   unsigned long long threshold,
-                                  unsigned long long excess);
+                                  unsigned long long excess,
+                                  long long seconds, unsigned int micros);
 
 int qemuMonitorStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index a9070fe..b4c7118 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -59,41 +59,73 @@ VIR_LOG_INIT("qemu.qemu_monitor_json");
 
 #define LINE_ENDING "\r\n"
 
-static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data);
-static void qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data,
+                                          long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data,
+                                       long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data,
+                                           long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data,
+                                      long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data,
+                                        long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data,
+                                           long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data,
+                                          long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data,
+                                         long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                            long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                              long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                 long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                 long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon, virJSONValuePtr data,
+                                            long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon, virJSONValuePtr data,
+                                          long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data,
+                                           long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                   long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                  long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data,
+                                            long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                    long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon, virJSONValuePtr data,
+                                              long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                 long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data,
+                                             long long seconds, unsigned int micros);
+static void qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                long long seconds, unsigned int micros);
 
 typedef struct {
     const char *type;
-    void (*handler)(qemuMonitorPtr mon, virJSONValuePtr data);
+    void (*handler)(qemuMonitorPtr mon, virJSONValuePtr data,
+                    long long seconds, unsigned int micros);
 } qemuEventHandler;
 
 static qemuEventHandler eventHandlers[] = {
@@ -146,7 +178,6 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
     const char *type;
     qemuEventHandler *handler;
     virJSONValuePtr data;
-    char *details = NULL;
     virJSONValuePtr timestamp;
     long long seconds = -1;
     unsigned int micros = 0;
@@ -161,23 +192,20 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
     }
 
     /* Not all events have data; and event reporting is best-effort only */
-    if ((data = virJSONValueObjectGet(obj, "data")))
-        details = virJSONValueToString(data, false);
+    ignore_value(data = virJSONValueObjectGet(obj, "data"));
     if ((timestamp = virJSONValueObjectGet(obj, "timestamp"))) {
         ignore_value(virJSONValueObjectGetNumberLong(timestamp, "seconds",
                                                      &seconds));
         ignore_value(virJSONValueObjectGetNumberUint(timestamp, "microseconds",
                                                      &micros));
     }
-    qemuMonitorEmitEvent(mon, type, seconds, micros, details);
-    VIR_FREE(details);
 
     handler = bsearch(type, eventHandlers, ARRAY_CARDINALITY(eventHandlers),
                       sizeof(eventHandlers[0]), qemuMonitorEventCompare);
     if (handler) {
         VIR_DEBUG("handle %s handler=%p data=%p", type,
                   handler->handler, data);
-        (handler->handler)(mon, data);
+        (handler->handler)(mon, data, seconds, micros);
     }
     return 0;
 }
@@ -523,7 +551,8 @@ qemuMonitorJSONKeywordStringToJSON(const char *str, const char *firstkeyword)
 }
 
 
-static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data,
+                                          long long seconds, unsigned int micros)
 {
     bool guest = false;
     virTristateBool guest_initiated = VIR_TRISTATE_BOOL_ABSENT;
@@ -531,27 +560,35 @@ static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr da
     if (data && virJSONValueObjectGetBoolean(data, "guest", &guest) == 0)
         guest_initiated = guest ? VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
 
-    qemuMonitorEmitShutdown(mon, guest_initiated);
+    qemuMonitorEmitShutdown(mon, guest_initiated, seconds, micros);
 }
 
-static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
+static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon,
+                                       virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                       long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitReset(mon);
+    qemuMonitorEmitReset(mon, seconds, micros);
 }
 
-static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
+static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon,
+                                           virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                           long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitPowerdown(mon);
+    qemuMonitorEmitPowerdown(mon, seconds, micros);
 }
 
-static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
+static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon,
+                                      virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                      long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitStop(mon);
+    qemuMonitorEmitStop(mon, seconds, micros);
 }
 
-static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
+static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon,
+                                        virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                        long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitResume(mon);
+    qemuMonitorEmitResume(mon, seconds, micros);
 }
 
 
@@ -599,7 +636,9 @@ qemuMonitorJSONGuestPanicExtractInfo(virJSONValuePtr data)
 
 static void
 qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon,
-                                virJSONValuePtr data)
+                                virJSONValuePtr data,
+                                long long seconds,
+                                unsigned int micros)
 {
     virJSONValuePtr infojson = virJSONValueObjectGetObject(data, "info");
     qemuMonitorEventPanicInfoPtr info = NULL;
@@ -607,25 +646,27 @@ qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon,
     if (infojson)
         info = qemuMonitorJSONGuestPanicExtractInfo(infojson);
 
-    qemuMonitorEmitGuestPanic(mon, info);
+    qemuMonitorEmitGuestPanic(mon, info, seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data,
+                                           long long seconds, unsigned int micros)
 {
     long long offset = 0;
     if (virJSONValueObjectGetNumberLong(data, "offset", &offset) < 0) {
         VIR_WARN("missing offset in RTC change event");
         offset = 0;
     }
-    qemuMonitorEmitRTCChange(mon, offset);
+    qemuMonitorEmitRTCChange(mon, offset, seconds, micros);
 }
 
 VIR_ENUM_DECL(qemuMonitorWatchdogAction)
 VIR_ENUM_IMPL(qemuMonitorWatchdogAction, VIR_DOMAIN_EVENT_WATCHDOG_LAST,
               "none", "pause", "reset", "poweroff", "shutdown", "debug", "inject-nmi");
 
-static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data,
+                                          long long seconds, unsigned int micros)
 {
     const char *action;
     int actionID;
@@ -639,7 +680,7 @@ static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr da
     } else {
             actionID = VIR_DOMAIN_EVENT_WATCHDOG_NONE;
     }
-    qemuMonitorEmitWatchdog(mon, actionID);
+    qemuMonitorEmitWatchdog(mon, actionID, seconds, micros);
 }
 
 VIR_ENUM_DECL(qemuMonitorIOErrorAction)
@@ -648,7 +689,8 @@ VIR_ENUM_IMPL(qemuMonitorIOErrorAction, VIR_DOMAIN_EVENT_IO_ERROR_LAST,
 
 
 static void
-qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data)
+qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data,
+                             long long seconds, unsigned int micros)
 {
     const char *device;
     const char *action;
@@ -676,7 +718,7 @@ qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data)
         actionID = VIR_DOMAIN_EVENT_IO_ERROR_NONE;
     }
 
-    qemuMonitorEmitIOError(mon, device, actionID, reason);
+    qemuMonitorEmitIOError(mon, device, actionID, reason, seconds, micros);
 }
 
 
@@ -688,7 +730,8 @@ VIR_ENUM_IMPL(qemuMonitorGraphicsAddressFamily,
 static void
 qemuMonitorJSONHandleGraphicsVNC(qemuMonitorPtr mon,
                                  virJSONValuePtr data,
-                                 int phase)
+                                 int phase,
+                                 long long seconds, unsigned int micros)
 {
     const char *localNode, *localService, *localFamily;
     const char *remoteNode, *remoteService, *remoteFamily;
@@ -753,31 +796,39 @@ qemuMonitorJSONHandleGraphicsVNC(qemuMonitorPtr mon,
     qemuMonitorEmitGraphics(mon, phase,
                             localFamilyID, localNode, localService,
                             remoteFamilyID, remoteNode, remoteService,
-                            authScheme, x509dname, saslUsername);
+                            authScheme, x509dname, saslUsername,
+                            seconds, micros);
 }
 
-static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                            long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
+    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT,
+                                     seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
+    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
+                                     seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                               long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
+    qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
+                                     seconds, micros);
 }
 
 
 static void
 qemuMonitorJSONHandleGraphicsSPICE(qemuMonitorPtr mon,
                                    virJSONValuePtr data,
-                                   int phase)
+                                   int phase,
+                                   long long seconds, unsigned int micros)
 {
     const char *lhost, *lport, *lfamily;
     const char *rhost, *rport, *rfamily;
@@ -834,31 +885,39 @@ qemuMonitorJSONHandleGraphicsSPICE(qemuMonitorPtr mon,
     }
 
     qemuMonitorEmitGraphics(mon, phase, lfamilyID, lhost, lport, rfamilyID,
-                            rhost, rport, auth, NULL, NULL);
+                            rhost, rport, auth, NULL, NULL,
+                            seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                              long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
+    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT,
+                                       seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                 long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
+    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
+                                       seconds, micros);
 }
 
 
-static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data)
+static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data,
+                                                 long long seconds, unsigned int micros)
 {
-    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
+    qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
+                                       seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon,
                                   virJSONValuePtr data,
-                                  int event)
+                                  int event,
+                                  long long seconds, unsigned int micros)
 {
     const char *device;
     const char *type_str;
@@ -908,12 +967,13 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon,
     }
 
  out:
-    qemuMonitorEmitBlockJob(mon, device, type, event);
+    qemuMonitorEmitBlockJob(mon, device, type, event, seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon,
-                                virJSONValuePtr data)
+                                virJSONValuePtr data,
+                                long long seconds, unsigned int micros)
 {
     const char *devAlias = NULL;
     bool trayOpened;
@@ -934,50 +994,58 @@ qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon,
     else
         reason = VIR_DOMAIN_EVENT_TRAY_CHANGE_CLOSE;
 
-    qemuMonitorEmitTrayChange(mon, devAlias, reason);
+    qemuMonitorEmitTrayChange(mon, devAlias, reason, seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon,
-                              virJSONValuePtr data ATTRIBUTE_UNUSED)
+                              virJSONValuePtr data ATTRIBUTE_UNUSED,
+                              long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitPMWakeup(mon);
+    qemuMonitorEmitPMWakeup(mon, micros, seconds);
 }
 
 static void
 qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon,
-                               virJSONValuePtr data ATTRIBUTE_UNUSED)
+                               virJSONValuePtr data ATTRIBUTE_UNUSED,
+                               long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitPMSuspend(mon);
+    qemuMonitorEmitPMSuspend(mon, seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon,
-                                       virJSONValuePtr data)
+                                       virJSONValuePtr data,
+                                       long long seconds, unsigned int micros)
 {
     qemuMonitorJSONHandleBlockJobImpl(mon, data,
-                                      VIR_DOMAIN_BLOCK_JOB_COMPLETED);
+                                      VIR_DOMAIN_BLOCK_JOB_COMPLETED,
+                                      seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon,
-                                       virJSONValuePtr data)
+                                       virJSONValuePtr data,
+                                       long long seconds, unsigned int micros)
 {
     qemuMonitorJSONHandleBlockJobImpl(mon, data,
-                                      VIR_DOMAIN_BLOCK_JOB_CANCELED);
+                                      VIR_DOMAIN_BLOCK_JOB_CANCELED,
+                                      seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon,
-                                   virJSONValuePtr data)
+                                   virJSONValuePtr data,
+                                   long long seconds, unsigned int micros)
 {
     qemuMonitorJSONHandleBlockJobImpl(mon, data,
-                                      VIR_DOMAIN_BLOCK_JOB_READY);
+                                      VIR_DOMAIN_BLOCK_JOB_READY, seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
-                                   virJSONValuePtr data)
+                                   virJSONValuePtr data,
+                                   long long seconds, unsigned int micros)
 {
     unsigned long long actual = 0;
     if (virJSONValueObjectGetNumberUlong(data, "actual", &actual) < 0) {
@@ -985,18 +1053,20 @@ qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
         return;
     }
     actual = VIR_DIV_UP(actual, 1024);
-    qemuMonitorEmitBalloonChange(mon, actual);
+    qemuMonitorEmitBalloonChange(mon, actual, seconds, micros);
 }
 
 static void
 qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon,
-                                   virJSONValuePtr data ATTRIBUTE_UNUSED)
+                                   virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                   long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitPMSuspendDisk(mon);
+    qemuMonitorEmitPMSuspendDisk(mon, seconds, micros);
 }
 
 static void
-qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data)
+qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data,
+                                   long long seconds, unsigned int micros)
 {
     const char *device;
 
@@ -1005,12 +1075,13 @@ qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data)
         return;
     }
 
-    qemuMonitorEmitDeviceDeleted(mon, device);
+    qemuMonitorEmitDeviceDeleted(mon, device, seconds, micros);
 }
 
 
 static void
-qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data)
+qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data,
+                                        long long seconds, unsigned int micros)
 {
     const char *name;
 
@@ -1019,13 +1090,14 @@ qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data
         return;
     }
 
-    qemuMonitorEmitNicRxFilterChanged(mon, name);
+    qemuMonitorEmitNicRxFilterChanged(mon, name, seconds, micros);
 }
 
 
 static void
 qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon,
-                                  virJSONValuePtr data)
+                                  virJSONValuePtr data,
+                                  long long seconds, unsigned int micros)
 {
     const char *name;
     bool connected;
@@ -1040,21 +1112,23 @@ qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon,
         return;
     }
 
-    qemuMonitorEmitSerialChange(mon, name, connected);
+    qemuMonitorEmitSerialChange(mon, name, connected, seconds, micros);
 }
 
 
 static void
 qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon,
-                                   virJSONValuePtr data ATTRIBUTE_UNUSED)
+                                   virJSONValuePtr data ATTRIBUTE_UNUSED,
+                                   long long seconds, unsigned int micros)
 {
-    qemuMonitorEmitSpiceMigrated(mon);
+    qemuMonitorEmitSpiceMigrated(mon, seconds, micros);
 }
 
 
 static void
 qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon,
-                                     virJSONValuePtr data)
+                                     virJSONValuePtr data,
+                                     long long seconds, unsigned int micros)
 {
     const char *str;
     int status;
@@ -1069,13 +1143,14 @@ qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon,
         return;
     }
 
-    qemuMonitorEmitMigrationStatus(mon, status);
+    qemuMonitorEmitMigrationStatus(mon, status, seconds, micros);
 }
 
 
 static void
 qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon,
-                                   virJSONValuePtr data)
+                                   virJSONValuePtr data,
+                                   long long seconds, unsigned int micros)
 {
     int pass;
 
@@ -1084,12 +1159,13 @@ qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon,
         return;
     }
 
-    qemuMonitorEmitMigrationPass(mon, pass);
+    qemuMonitorEmitMigrationPass(mon, pass, seconds, micros);
 }
 
 
 static void
-qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data)
+qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data,
+                                 long long seconds, unsigned int micros)
 {
     virJSONValuePtr info;
     const char *alias;
@@ -1116,7 +1192,8 @@ qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data)
     if (virJSONValueObjectGetNumberUint(info, "status", &status) < 0)
         goto error;
 
-    qemuMonitorEmitAcpiOstInfo(mon, alias, slotType, slot, source, status);
+    qemuMonitorEmitAcpiOstInfo(mon, alias, slotType, slot, source, status,
+                               seconds, micros);
     return;
 
  error:
@@ -1126,7 +1203,8 @@ qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data)
 
 
 static void
-qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data)
+qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data,
+                                    long long seconds, unsigned int micros)
 {
     const char *nodename;
     unsigned long long threshold;
@@ -1141,7 +1219,8 @@ qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data)
     if (virJSONValueObjectGetNumberUlong(data, "amount-exceeded", &excess) < 0)
         goto error;
 
-    qemuMonitorEmitBlockThreshold(mon, nodename, threshold, excess);
+    qemuMonitorEmitBlockThreshold(mon, nodename, threshold, excess,
+                                  seconds, micros);
     return;
 
  error:
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 8e6498e..ee8bae5 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -82,6 +82,12 @@
 
 VIR_LOG_INIT("qemu.qemu_process");
 
+typedef struct {
+    qemuMonitorEventType type;
+    void (*handler_func)(qemuEventPtr ev, void *opaque);
+} qemuEventFuncTable;
+
+
 /**
  * qemuProcessRemoveDomainStatus
  *
@@ -474,20 +480,24 @@ qemuProcessFindVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     return ret;
 }
 
-
-static int
-qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                       virDomainObjPtr vm,
-                       void *opaque)
+static void
+qemuProcessEventHandleReset(qemuEventPtr ev,
+                            void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event;
     qemuDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    int ret = -1;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
 
+    if (!ev->vm) {
+        VIR_INFO("Dropping reset event for unknown VM");
+        return;
+    }
+    vm = ev->vm;
     event = virDomainEventRebootNewFromObj(vm);
     priv = vm->privateData;
     if (priv->agent)
@@ -516,12 +526,10 @@ qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         qemuDomainObjEndJob(driver, vm);
     }
 
-    ret = 0;
  cleanup:
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
-    return ret;
+    return;
 }
 
 
@@ -623,60 +631,69 @@ qemuProcessShutdownOrReboot(virQEMUDriverPtr driver,
 }
 
 
-static int
-qemuProcessHandleEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                       virDomainObjPtr vm,
-                       const char *eventName,
-                       long long seconds,
-                       unsigned int micros,
-                       const char *details,
-                       void *opaque)
+
+void
+qemuProcessEmitMonitorEvent(qemuEventPtr ev,
+                            void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
+    virDomainObjPtr vm;
+    const char * eventName;
 
-    VIR_DEBUG("vm=%p", vm);
+    if (!ev)
+        return;
+
+    vm = ev->vm;
+
+    eventName = qemuMonitorEventTypeToString(ev->ev_type);
+    VIR_DEBUG("vm=%s monitor event %s", vm->def->name, eventName);
 
-    virObjectLock(vm);
     event = virDomainQemuMonitorEventNew(vm->def->id, vm->def->name,
                                          vm->def->uuid, eventName,
-                                         seconds, micros, details);
-
-    virObjectUnlock(vm);
-    qemuDomainEventQueue(driver, event);
+                                         ev->seconds, ev->micros, NULL);
+    if (event)
+        qemuDomainEventQueue(driver, event);
 
-    return 0;
+    return;
 }
 
 
-static int
-qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm,
-                          virTristateBool guest_initiated,
-                          void *opaque)
+static void
+qemuProcessEventHandleShutdown(qemuEventPtr ev,
+
+                               void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     qemuDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
+    virTristateBool guest_initiated;
     virObjectEventPtr event = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     int detail = 0;
 
-    VIR_DEBUG("vm=%p", vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
 
-    virObjectLock(vm);
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping SHUTDOWN event");
+        goto exit;
+    }
 
+    VIR_DEBUG("Processing SHUTDOWN event for VM %s", vm->def->name);
     priv = vm->privateData;
     if (priv->gotShutdown) {
         VIR_DEBUG("Ignoring repeated SHUTDOWN event from domain %s",
                   vm->def->name);
-        goto unlock;
+        goto exit;
     } else if (!virDomainObjIsActive(vm)) {
         VIR_DEBUG("Ignoring SHUTDOWN event from inactive domain %s",
                   vm->def->name);
-        goto unlock;
+        goto exit;
     }
     priv->gotShutdown = true;
-
+    guest_initiated = ev->evData.ev_shutdown.guest_initiated;
     VIR_DEBUG("Transitioned guest %s to shutdown state",
               vm->def->name);
     virDomainObjSetState(vm,
@@ -710,34 +727,39 @@ qemuProcessHandleShutdown(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SHUTDOWN);
 
     qemuProcessShutdownOrReboot(driver, vm);
-
- unlock:
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
-    virObjectUnref(cfg);
 
-    return 0;
+    virObjectUnref(cfg);
+exit:
+    return;
 }
 
-
-static int
-qemuProcessHandleStop(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                      virDomainObjPtr vm,
-                      void *opaque)
+static void
+qemuProcessEventHandleStop(qemuEventPtr ev,
+                           void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virDomainPausedReason reason = VIR_DOMAIN_PAUSED_UNKNOWN;
     virDomainEventSuspendedDetailType detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping STOP event");
+        goto exit;
+    }
 
-    virObjectLock(vm);
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
 
         if (priv->gotShutdown) {
             VIR_DEBUG("Ignoring STOP event after SHUTDOWN");
-            goto unlock;
+            goto exit;
         }
 
         if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
@@ -776,31 +798,38 @@ qemuProcessHandleStop(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         }
     }
 
- unlock:
-    virObjectUnlock(vm);
+exit:
     qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
 
-    return 0;
+    return;
 }
 
 
-static int
-qemuProcessHandleResume(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                        virDomainObjPtr vm,
+static void
+qemuProcessEventHandleResume(qemuEventPtr ev,
                         void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
+    virDomainObjPtr vm;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping RESUME event");
+        goto exit;
+    }
+
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
 
         if (priv->gotShutdown) {
             VIR_DEBUG("Ignoring RESUME event after SHUTDOWN");
-            goto unlock;
+            goto exit;
         }
 
         VIR_DEBUG("Transitioned guest %s out of paused into resumed state",
@@ -818,25 +847,32 @@ qemuProcessHandleResume(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         }
     }
 
- unlock:
-    virObjectUnlock(vm);
+exit:
     qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
-    return 0;
+    return;
 }
 
-static int
-qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                           virDomainObjPtr vm,
-                           long long offset,
-                           void *opaque)
+static void
+qemuProcessEventHandleRTCChange(qemuEventPtr ev,
+                                void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
+    virDomainObjPtr vm;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    unsigned long long offset;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping RTC event");
+        goto exit;
+    }
 
+    offset = ev->evData.ev_rtc.offset;
     if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) {
         /* when a basedate is manually given on the qemu commandline
          * rather than simply "-rtc base=utc", the offset sent by qemu
@@ -862,26 +898,33 @@ qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
 
     event = virDomainEventRTCChangeNewFromObj(vm, offset);
 
-    virObjectUnlock(vm);
-
-    qemuDomainEventQueue(driver, event);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
-    return 0;
+exit:
+    return;
 }
 
-
-static int
-qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm,
-                          int action,
-                          void *opaque)
+static void
+qemuProcessEventHandleWatchdog1(qemuEventPtr ev,
+                               void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr watchdogEvent = NULL;
     virObjectEventPtr lifecycleEvent = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+    int action;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Watchdog event");
+        goto exit;
+    }
+    action = ev->evData.ev_watchdog.action;
     watchdogEvent = virDomainEventWatchdogNewFromObj(vm, action);
 
     if (action == VIR_DOMAIN_EVENT_WATCHDOG_PAUSE &&
@@ -923,22 +966,16 @@ qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         }
     }
 
-    if (vm)
-        virObjectUnlock(vm);
     qemuDomainEventQueue(driver, watchdogEvent);
     qemuDomainEventQueue(driver, lifecycleEvent);
 
     virObjectUnref(cfg);
-    return 0;
+exit:
+    return;
 }
 
-
-static int
-qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                         virDomainObjPtr vm,
-                         const char *diskAlias,
-                         int action,
-                         const char *reason,
+static void
+qemuProcessEventHandleIOError(qemuEventPtr ev,
                          void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
@@ -949,8 +986,24 @@ qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     const char *devAlias;
     virDomainDiskDefPtr disk;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+    const char *diskAlias;
+    int action;
+    const char *reason;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping IO Error event");
+        goto exit;
+    }
+
+    diskAlias = ev->evData.ev_IOErr.device;
+    action = ev->evData.ev_IOErr.action;
+    reason = ev->evData.ev_IOErr.reason;
 
-    virObjectLock(vm);
     disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias);
 
     if (disk) {
@@ -975,7 +1028,7 @@ qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_IOERROR);
         lifecycleEvent = virDomainEventLifecycleNewFromObj(vm,
                                                   VIR_DOMAIN_EVENT_SUSPENDED,
-                                                  VIR_DOMAIN_EVENT_SUSPENDED_IOERROR);
+                                                  VIR_DOMAIN_PAUSED_IOERROR);
 
         VIR_FREE(priv->lockState);
         if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
@@ -985,32 +1038,45 @@ qemuProcessHandleIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
             VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
     }
-    virObjectUnlock(vm);
 
     qemuDomainEventQueue(driver, ioErrorEvent);
     qemuDomainEventQueue(driver, ioErrorEvent2);
     qemuDomainEventQueue(driver, lifecycleEvent);
+
+exit:
     virObjectUnref(cfg);
-    return 0;
+    VIR_FREE(ev->evData.ev_IOErr.device);
+    VIR_FREE(ev->evData.ev_IOErr.reason);
+    return;
 }
 
-static int
-qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm,
-                          const char *diskAlias,
-                          int type,
-                          int status,
-                          void *opaque)
+static void
+qemuProcessEventHandleBlockJob(qemuEventPtr ev,
+                               void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     struct qemuProcessEvent *processEvent = NULL;
     virDomainDiskDefPtr disk;
     qemuDomainDiskPrivatePtr diskPriv;
     char *data = NULL;
+    virDomainObjPtr vm;
+    const char *diskAlias;
+    int type, status;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
 
-    VIR_DEBUG("Block job for device %s (domain: %p,%s) type %d status %d",
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Block Job event");
+        goto cleanup;
+    }
+
+    diskAlias = ev->evData.ev_blockJob.device;
+    type = ev->evData.ev_blockJob.type;
+    status = ev->evData.ev_blockJob.status;
+
+    VIR_INFO("Block job for device %s (domain: %p,%s) type %d status %d",
               diskAlias, vm, vm->def->name, type, status);
 
     if (!(disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias)))
@@ -1043,8 +1109,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     }
 
  cleanup:
-    virObjectUnlock(vm);
-    return 0;
+    return;
  error:
     if (processEvent)
         VIR_FREE(processEvent->data);
@@ -1052,21 +1117,9 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     goto cleanup;
 }
 
-
-static int
-qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm,
-                          int phase,
-                          int localFamily,
-                          const char *localNode,
-                          const char *localService,
-                          int remoteFamily,
-                          const char *remoteNode,
-                          const char *remoteService,
-                          const char *authScheme,
-                          const char *x509dname,
-                          const char *saslUsername,
-                          void *opaque)
+static void
+qemuProcessEventHandleGraphics(qemuEventPtr ev,
+                               void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event;
@@ -1074,49 +1127,65 @@ qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     virDomainEventGraphicsAddressPtr remoteAddr = NULL;
     virDomainEventGraphicsSubjectPtr subject = NULL;
     size_t i;
+    virDomainObjPtr vm;
+    struct qemuEventGraphicsData *data;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Graphics event");
+        goto exit;
+    }
+    data = &(ev->evData.ev_graphics);
 
     if (VIR_ALLOC(localAddr) < 0)
         goto error;
-    localAddr->family = localFamily;
-    if (VIR_STRDUP(localAddr->service, localService) < 0 ||
-        VIR_STRDUP(localAddr->node, localNode) < 0)
+
+    localAddr->family = data->localFamilyID;
+    if (VIR_STRDUP(localAddr->service, data->localService) < 0 ||
+        VIR_STRDUP(localAddr->node, data->localNode) < 0)
         goto error;
 
     if (VIR_ALLOC(remoteAddr) < 0)
         goto error;
-    remoteAddr->family = remoteFamily;
-    if (VIR_STRDUP(remoteAddr->service, remoteService) < 0 ||
-        VIR_STRDUP(remoteAddr->node, remoteNode) < 0)
+    remoteAddr->family = data->remoteFamilyID;
+    if (VIR_STRDUP(remoteAddr->service, data->remoteService) < 0 ||
+        VIR_STRDUP(remoteAddr->node, data->remoteNode) < 0)
         goto error;
 
     if (VIR_ALLOC(subject) < 0)
         goto error;
-    if (x509dname) {
+    if (data->x509dname) {
         if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
             goto error;
         subject->nidentity++;
         if (VIR_STRDUP(subject->identities[subject->nidentity-1].type, "x509dname") < 0 ||
-            VIR_STRDUP(subject->identities[subject->nidentity-1].name, x509dname) < 0)
+            VIR_STRDUP(subject->identities[subject->nidentity-1].name,
+                                                             data->x509dname) < 0)
             goto error;
     }
-    if (saslUsername) {
+    if (data->saslUsername) {
         if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
             goto error;
         subject->nidentity++;
         if (VIR_STRDUP(subject->identities[subject->nidentity-1].type, "saslUsername") < 0 ||
-            VIR_STRDUP(subject->identities[subject->nidentity-1].name, saslUsername) < 0)
+            VIR_STRDUP(subject->identities[subject->nidentity-1].name,
+                                                          data->saslUsername) < 0)
             goto error;
     }
 
-    virObjectLock(vm);
-    event = virDomainEventGraphicsNewFromObj(vm, phase, localAddr, remoteAddr, authScheme, subject);
-    virObjectUnlock(vm);
+    event = virDomainEventGraphicsNewFromObj(vm, data->phase,
+                                             localAddr, remoteAddr,
+                                             data->authScheme,
+                                             subject);
 
     qemuDomainEventQueue(driver, event);
 
-    return 0;
+    goto exit;
 
- error:
+error:
     if (localAddr) {
         VIR_FREE(localAddr->service);
         VIR_FREE(localAddr->node);
@@ -1136,22 +1205,41 @@ qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         VIR_FREE(subject);
     }
 
-    return -1;
+exit:
+    VIR_FREE(ev->evData.ev_graphics.localNode);
+    VIR_FREE(ev->evData.ev_graphics.localService);
+    VIR_FREE(ev->evData.ev_graphics.remoteNode);
+    VIR_FREE(ev->evData.ev_graphics.remoteService);
+    VIR_FREE(ev->evData.ev_graphics.x509dname);
+    VIR_FREE(ev->evData.ev_graphics.saslUsername);
+    VIR_FREE(ev->evData.ev_graphics.authScheme);
+    return;
 }
 
-static int
-qemuProcessHandleTrayChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                            virDomainObjPtr vm,
-                            const char *devAlias,
-                            int reason,
-                            void *opaque)
+static void
+qemuProcessEventHandleTrayChange(qemuEventPtr ev,
+                                 void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virDomainDiskDefPtr disk;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+    const char *devAlias;
+    int reason;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Graphics event");
+        goto exit;
+    }
+
+    devAlias = ev->evData.ev_tray.devAlias;
+    reason = ev->evData.ev_tray.reason;
 
-    virObjectLock(vm);
     disk = qemuProcessFindDomainDiskByAlias(vm, devAlias);
 
     if (disk) {
@@ -1168,27 +1256,36 @@ qemuProcessHandleTrayChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
             VIR_WARN("Unable to save status on vm %s after tray moved event",
                      vm->def->name);
         }
-
-        virDomainObjBroadcast(vm);
+// Why the broadcast here?
+//        virDomainObjBroadcast(vm);
     }
 
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
-    return 0;
+exit:
+    VIR_FREE(ev->evData.ev_tray.devAlias);
+    return;
 }
 
-static int
-qemuProcessHandlePMWakeup(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                          virDomainObjPtr vm,
-                          void *opaque)
+static void
+qemuProcessEventHandlePMWakeup(qemuEventPtr ev,
+                               void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virObjectEventPtr lifecycleEvent = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping PM Wakeup event");
+        goto exit;
+    }
 
-    virObjectLock(vm);
     event = virDomainEventPMWakeupNewFromObj(vm);
 
     /* Don't set domain status back to running if it wasn't paused
@@ -1210,24 +1307,32 @@ qemuProcessHandlePMWakeup(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         }
     }
 
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
     qemuDomainEventQueue(driver, lifecycleEvent);
     virObjectUnref(cfg);
-    return 0;
+exit:
+    return;
 }
 
-static int
-qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                           virDomainObjPtr vm,
-                           void *opaque)
+static void
+qemuProcessEventHandlePMSuspend(qemuEventPtr ev,
+                                void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virObjectEventPtr lifecycleEvent = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping PM Suspend event");
+        goto exit;
+    }
 
-    virObjectLock(vm);
     event = virDomainEventPMSuspendNewFromObj(vm);
 
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
@@ -1251,25 +1356,33 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
             qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
     }
 
-    virObjectUnlock(vm);
-
     qemuDomainEventQueue(driver, event);
     qemuDomainEventQueue(driver, lifecycleEvent);
     virObjectUnref(cfg);
-    return 0;
+exit:
+    return;
 }
 
-static int
-qemuProcessHandleBalloonChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               unsigned long long actual,
-                               void *opaque)
+static void
+qemuProcessEventHandleBalloonChange(qemuEventPtr ev,
+                                    void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
+    unsigned long long actual;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Balloon event");
+        goto exit;
+    }
+
+    actual = ev->evData.ev_balloon.actual;
     event = virDomainEventBalloonChangeNewFromObj(vm, actual);
 
     VIR_DEBUG("Updating balloon from %lld to %lld kb",
@@ -1279,24 +1392,30 @@ qemuProcessHandleBalloonChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
         VIR_WARN("unable to save domain status with balloon change");
 
-    virObjectUnlock(vm);
-
     qemuDomainEventQueue(driver, event);
     virObjectUnref(cfg);
-    return 0;
+exit:
+    return;
 }
 
-static int
-qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               void *opaque)
+static void
+qemuProcessEventHandlePMSuspendDisk(qemuEventPtr ev,
+                                    void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
     virObjectEventPtr lifecycleEvent = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainObjPtr vm;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping PM Suspend disk event");
+        goto exit;
+    }
     event = virDomainEventPMSuspendDiskNewFromObj(vm);
 
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
@@ -1320,28 +1439,35 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
             qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
     }
 
-    virObjectUnlock(vm);
-
     qemuDomainEventQueue(driver, event);
     qemuDomainEventQueue(driver, lifecycleEvent);
     virObjectUnref(cfg);
-
-    return 0;
+exit:
+    return;
 }
 
 
-static int
-qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                            virDomainObjPtr vm,
-                            qemuMonitorEventPanicInfoPtr info,
-                            void *opaque)
+static void
+qemuProcessEventHandleGuestPanic(qemuEventPtr ev,
+                                 void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     struct qemuProcessEvent *processEvent;
+    virDomainObjPtr vm;
+    qemuMonitorEventPanicInfoPtr info;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Guest Panic event");
+        goto exit;
+    }
+
+    info = ev->evData.ev_panic.info;
     if (VIR_ALLOC(processEvent) < 0)
-        goto cleanup;
+        goto exit;
 
     processEvent->eventType = QEMU_PROCESS_EVENT_GUESTPANIC;
     processEvent->action = vm->def->onCrash;
@@ -1357,26 +1483,31 @@ qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         VIR_FREE(processEvent);
     }
 
- cleanup:
-    if (vm)
-        virObjectUnlock(vm);
-
-    return 0;
+exit:
+    return;
 }
 
 
-int
-qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               const char *devAlias,
-                               void *opaque)
+static void
+qemuProcessEventHandleDeviceDeleted(qemuEventPtr ev,
+                                    void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     struct qemuProcessEvent *processEvent = NULL;
     char *data;
+    virDomainObjPtr vm;
+    const char *devAlias;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Device deleted event");
+        goto cleanup;
+    }
 
+    devAlias = ev->evData.ev_deviceDel.device;
     VIR_DEBUG("Device %s removed from domain %p %s",
               devAlias, vm, vm->def->name);
 
@@ -1400,8 +1531,8 @@ qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     }
 
  cleanup:
-    virObjectUnlock(vm);
-    return 0;
+    VIR_FREE(ev->evData.ev_deviceDel.device);
+    return;
  error:
     if (processEvent)
         VIR_FREE(processEvent->data);
@@ -1444,20 +1575,34 @@ qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
  *  Note that qemu does not emit the event for all the documented sources or
  *  devices.
  */
-static int
-qemuProcessHandleAcpiOstInfo(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                             virDomainObjPtr vm,
-                             const char *alias,
-                             const char *slotType,
-                             const char *slot,
-                             unsigned int source,
-                             unsigned int status,
-                             void *opaque)
+
+static void
+qemuProcessEventHandleAcpiOstInfo(qemuEventPtr ev,
+                                  void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
+    virDomainObjPtr vm;
+    const char *alias;
+    const char *slotType;
+    const char *slot;
+    unsigned int source;
+    unsigned int status;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping ACPI event");
+        goto exit;
+    }
+
+    alias = ev->evData.ev_acpi.alias;
+    slotType = ev->evData.ev_acpi.slotType;
+    slot = ev->evData.ev_acpi.slot;
+    source = ev->evData.ev_acpi.source;
+    status = ev->evData.ev_acpi.status;
 
     VIR_DEBUG("ACPI OST info for device %s domain %p %s. "
               "slotType='%s' slot='%s' source=%u status=%u",
@@ -1471,20 +1616,19 @@ qemuProcessHandleAcpiOstInfo(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         event = virDomainEventDeviceRemovalFailedNewFromObj(vm, alias);
     }
 
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
 
-    return 0;
+exit:
+    VIR_FREE(ev->evData.ev_acpi.alias);
+    VIR_FREE(ev->evData.ev_acpi.slotType);
+    VIR_FREE(ev->evData.ev_acpi.slot);
+    return;
 }
 
 
-static int
-qemuProcessHandleBlockThreshold(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                                virDomainObjPtr vm,
-                                const char *nodename,
-                                unsigned long long threshold,
-                                unsigned long long excess,
-                                void *opaque)
+static void
+qemuProcessEventHandleBlockThreshold(qemuEventPtr ev,
+                                     void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     virObjectEventPtr event = NULL;
@@ -1493,8 +1637,23 @@ qemuProcessHandleBlockThreshold(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     unsigned int idx;
     char *dev = NULL;
     const char *path = NULL;
+    virDomainObjPtr vm;
+    const char *nodename;
+    unsigned long long threshold;
+    unsigned long long excess;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Block Threshold event");
+        goto exit;
+    }
+
+    nodename = ev->evData.ev_threshold.nodename;
+    threshold = ev->evData.ev_threshold.threshold;
+    excess = ev->evData.ev_threshold.excess;
 
     VIR_DEBUG("BLOCK_WRITE_THRESHOLD event for block node '%s' in domain %p %s:"
               "threshold '%llu' exceeded by '%llu'",
@@ -1511,25 +1670,33 @@ qemuProcessHandleBlockThreshold(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         }
     }
 
-    virObjectUnlock(vm);
     qemuDomainEventQueue(driver, event);
-
-    return 0;
+exit:
+    VIR_FREE(ev->evData.ev_threshold.nodename);
+    return;
 }
 
 
-static int
-qemuProcessHandleNicRxFilterChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                                    virDomainObjPtr vm,
-                                    const char *devAlias,
-                                    void *opaque)
+static void
+qemuProcessEventHandleNicRxFilterChanged(qemuEventPtr ev,
+                                         void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     struct qemuProcessEvent *processEvent = NULL;
     char *data;
+    virDomainObjPtr vm;
+    char *devAlias;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Nic Filter Change event");
+        goto exit;
+    }
 
+    devAlias = ev->evData.ev_nic.devAlias;
     VIR_DEBUG("Device %s RX Filter changed in domain %p %s",
               devAlias, vm, vm->def->name);
 
@@ -1548,30 +1715,39 @@ qemuProcessHandleNicRxFilterChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         goto error;
     }
 
- cleanup:
-    virObjectUnlock(vm);
-    return 0;
+exit:
+    VIR_FREE(ev->evData.ev_nic.devAlias);
+    return;
  error:
     if (processEvent)
         VIR_FREE(processEvent->data);
     VIR_FREE(processEvent);
-    goto cleanup;
+    goto exit;
 }
 
 
-static int
-qemuProcessHandleSerialChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               const char *devAlias,
-                               bool connected,
-                               void *opaque)
+static void
+qemuProcessEventHandleSerialChanged(qemuEventPtr ev,
+                                    void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     struct qemuProcessEvent *processEvent = NULL;
     char *data;
+    virDomainObjPtr vm;
+    char *devAlias;
+    bool connected;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
 
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Serial Change event");
+        goto cleanup;
+    }
+
+    devAlias = ev->evData.ev_serial.devAlias;
+    connected = ev->evData.ev_serial.connected;
     VIR_DEBUG("Serial port %s state changed to '%d' in domain %p %s",
               devAlias, connected, vm, vm->def->name);
 
@@ -1592,8 +1768,8 @@ qemuProcessHandleSerialChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     }
 
  cleanup:
-    virObjectUnlock(vm);
-    return 0;
+    VIR_FREE(ev->evData.ev_serial.devAlias);
+    return;
  error:
     if (processEvent)
         VIR_FREE(processEvent->data);
@@ -1602,14 +1778,21 @@ qemuProcessHandleSerialChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
 }
 
 
-static int
-qemuProcessHandleSpiceMigrated(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               void *opaque ATTRIBUTE_UNUSED)
+static void
+qemuProcessEventHandleSpiceMigrated(qemuEventPtr ev,
+                                    void *opaque ATTRIBUTE_UNUSED)
 {
     qemuDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Spice Migrated event");
+        goto cleanup;
+    }
 
     VIR_DEBUG("Spice migration completed for domain %p %s",
               vm, vm->def->name);
@@ -1621,28 +1804,37 @@ qemuProcessHandleSpiceMigrated(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     }
 
     priv->job.spiceMigrated = true;
-    virDomainObjBroadcast(vm);
+//    virDomainObjBroadcast(vm);
 
  cleanup:
-    virObjectUnlock(vm);
-    return 0;
+    return;
 }
 
 
-static int
-qemuProcessHandleMigrationStatus(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                                 virDomainObjPtr vm,
-                                 int status,
-                                 void *opaque ATTRIBUTE_UNUSED)
+static void
+qemuProcessEventHandleMigrationStatus(qemuEventPtr ev,
+                                      void *opaque ATTRIBUTE_UNUSED)
 {
     qemuDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
+    int status;
 
-    virObjectLock(vm);
 
+    if (!ev)
+        return;
+    vm = ev->vm;
+
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Migration Status event");
+        goto cleanup;
+    }
+
+    status = ev->evData.ev_migStatus.status;
     VIR_DEBUG("Migration of domain %p %s changed state to %s",
               vm, vm->def->name,
               qemuMonitorMigrationStatusTypeToString(status));
 
+
     priv = vm->privateData;
     if (priv->job.asyncJob == QEMU_ASYNC_JOB_NONE) {
         VIR_DEBUG("got MIGRATION event without a migration job");
@@ -1650,25 +1842,32 @@ qemuProcessHandleMigrationStatus(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     }
 
     priv->job.current->stats.status = status;
-    virDomainObjBroadcast(vm);
+//    virDomainObjBroadcast(vm);
 
  cleanup:
-    virObjectUnlock(vm);
-    return 0;
+    return;
 }
 
 
-static int
-qemuProcessHandleMigrationPass(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                               virDomainObjPtr vm,
-                               int pass,
-                               void *opaque)
+static void
+qemuProcessEventHandleMigrationPass(qemuEventPtr ev,
+                                    void *opaque)
 {
     virQEMUDriverPtr driver = opaque;
     qemuDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
+    int pass;
 
-    virObjectLock(vm);
+    if (!ev)
+        return;
+    vm = ev->vm;
 
+    if (!ev->vm) {
+        VIR_WARN("Unable to locate VM, dropping Migration Pass event");
+        goto cleanup;
+    }
+
+    pass = ev->evData.ev_migPass.pass;
     VIR_DEBUG("Migrating domain %p %s, iteration %d",
               vm, vm->def->name, pass);
 
@@ -1681,42 +1880,58 @@ qemuProcessHandleMigrationPass(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     qemuDomainEventQueue(driver,
                          virDomainEventMigrationIterationNewFromObj(vm, pass));
 
- cleanup:
-    virObjectUnlock(vm);
-    return 0;
+cleanup:
+    return;
 }
 
+static qemuEventFuncTable qemuEventFunctions[] = {
+    { QEMU_EVENT_ACPI_OST, qemuProcessEventHandleAcpiOstInfo, },
+    { QEMU_EVENT_BALLOON_CHANGE, qemuProcessEventHandleBalloonChange, },
+    { QEMU_EVENT_BLOCK_IO_ERROR, qemuProcessEventHandleIOError, },
+    { QEMU_EVENT_BLOCK_JOB, qemuProcessEventHandleBlockJob, },
+    { QEMU_EVENT_BLOCK_WRITE_THRESHOLD, qemuProcessEventHandleBlockThreshold, },
+    { QEMU_EVENT_DEVICE_DELETED, qemuProcessEventHandleDeviceDeleted, },
+    { QEMU_EVENT_DEVICE_TRAY_MOVED, qemuProcessEventHandleTrayChange, },
+    { QEMU_EVENT_GRAPHICS, qemuProcessEventHandleGraphics,},
+    { QEMU_EVENT_GUEST_PANICKED, qemuProcessEventHandleGuestPanic,},
+    { QEMU_EVENT_MIGRATION, qemuProcessEventHandleMigrationStatus,},
+    { QEMU_EVENT_MIGRATION_PASS, qemuProcessEventHandleMigrationPass,},
+    { QEMU_EVENT_NIC_RX_FILTER_CHANGED, qemuProcessEventHandleNicRxFilterChanged, },
+    { QEMU_EVENT_POWERDOWN, NULL, },
+    { QEMU_EVENT_RESET, qemuProcessEventHandleReset, },
+    { QEMU_EVENT_RESUME, qemuProcessEventHandleResume, },
+    { QEMU_EVENT_RTC_CHANGE, qemuProcessEventHandleRTCChange, },
+    { QEMU_EVENT_SHUTDOWN, qemuProcessEventHandleShutdown,},
+    { QEMU_EVENT_SPICE_MIGRATED, qemuProcessEventHandleSpiceMigrated, },
+    { QEMU_EVENT_STOP, qemuProcessEventHandleStop, },
+    { QEMU_EVENT_SUSPEND, qemuProcessEventHandlePMSuspend,},
+    { QEMU_EVENT_SUSPEND_DISK, qemuProcessEventHandlePMSuspendDisk,},
+    { QEMU_EVENT_SERIAL_CHANGE, qemuProcessEventHandleSerialChanged,},
+    { QEMU_EVENT_WAKEUP, qemuProcessEventHandlePMWakeup,},
+    { QEMU_EVENT_WATCHDOG, qemuProcessEventHandleWatchdog1,},
+};
+
+static int
+qemuProcessEnqueueEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+                        virDomainObjPtr vm ATTRIBUTE_UNUSED,
+                        qemuEventPtr ev,
+                        void *opaque)
+{
+    virQEMUDriverPtr driver = opaque;
+    /* Bad code alert: Fix this lookup to scan table for correct index.
+     * Works for now since event table is sorted */
+    ev->handler = qemuEventFunctions[ev->ev_type].handler_func;
+    return virEnqueueVMEvent(driver->ev_list, ev);
+}
 
 static qemuMonitorCallbacks monitorCallbacks = {
     .eofNotify = qemuProcessHandleMonitorEOF,
     .errorNotify = qemuProcessHandleMonitorError,
     .diskSecretLookup = qemuProcessFindVolumeQcowPassphrase,
-    .domainEvent = qemuProcessHandleEvent,
-    .domainShutdown = qemuProcessHandleShutdown,
-    .domainStop = qemuProcessHandleStop,
-    .domainResume = qemuProcessHandleResume,
-    .domainReset = qemuProcessHandleReset,
-    .domainRTCChange = qemuProcessHandleRTCChange,
-    .domainWatchdog = qemuProcessHandleWatchdog,
-    .domainIOError = qemuProcessHandleIOError,
-    .domainGraphics = qemuProcessHandleGraphics,
-    .domainBlockJob = qemuProcessHandleBlockJob,
-    .domainTrayChange = qemuProcessHandleTrayChange,
-    .domainPMWakeup = qemuProcessHandlePMWakeup,
-    .domainPMSuspend = qemuProcessHandlePMSuspend,
-    .domainBalloonChange = qemuProcessHandleBalloonChange,
-    .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk,
-    .domainGuestPanic = qemuProcessHandleGuestPanic,
-    .domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
-    .domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
-    .domainSerialChange = qemuProcessHandleSerialChanged,
-    .domainSpiceMigrated = qemuProcessHandleSpiceMigrated,
-    .domainMigrationStatus = qemuProcessHandleMigrationStatus,
-    .domainMigrationPass = qemuProcessHandleMigrationPass,
-    .domainAcpiOstInfo = qemuProcessHandleAcpiOstInfo,
-    .domainBlockThreshold = qemuProcessHandleBlockThreshold,
+    .domainEnqueueEvent = qemuProcessEnqueueEvent,
 };
 
+
 static void
 qemuProcessMonitorReportLogError(qemuMonitorPtr mon,
                                  const char *msg,
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index 814b86d..a2bbc4f 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -129,6 +129,8 @@ int qemuProcessFinishStartup(virConnectPtr conn,
                              bool startCPUs,
                              virDomainPausedReason pausedReason);
 
+void qemuProcessEmitMonitorEvent(qemuEventPtr ev,
+                                 void *opaque);
 typedef enum {
     VIR_QEMU_PROCESS_STOP_MIGRATED      = 1 << 0,
     VIR_QEMU_PROCESS_STOP_NO_RELABEL    = 1 << 1,
diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c
index 5e30fb0..94375a3 100644
--- a/tests/qemumonitortestutils.c
+++ b/tests/qemumonitortestutils.c
@@ -1013,7 +1013,7 @@ qemuMonitorTestErrorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
 static qemuMonitorCallbacks qemuMonitorTestCallbacks = {
     .eofNotify = qemuMonitorTestEOFNotify,
     .errorNotify = qemuMonitorTestErrorNotify,
-    .domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
+    .domainDeviceDeleted = NULL, //qemuProcessHandleDeviceDeleted,
 };
 
 
-- 
2.9.5

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]
  Powered by Linux