[libvirt] PATCH: 8/28: Thread safety for domain events code

Daniel P. Berrange berrange at redhat.com
Sun Nov 30 23:47:21 UTC 2008


This patch adds thread safety to the domain events processing code of
the QEMU driver. This entailed rather a large refactoring of the domain
events code and its quite complicated to explain.

- A convenient helper is added for creating event queues

        virDomainEventQueuePtr virDomainEventQueueNew(void);

- Convenient helpers are added for creating virDomainEventPtr instances
  from a variety of sources - each driver has different needs

   virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail);
   virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detail);
   virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail);
   virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail);

- The virDomainEvent struct held a reference to a virDomainPtr object.
  This is replaced with a direct triple (id, name, uuid), avoiding the
  need to instantiate virDomainPtr objects deep inside the QEMU code.

- The virDomainEventQueuePush() method is changed to take a
  virDomainEventPtr object, rather than a virDomainPtr object

These last two changes are important to allow safe re-entrancy of the 
event dispatch process. The virDomainEventPtr instance can be allocated
within a critical section lockde on the virDomainObjPtr instance, while
the event is queued outside the critical section, while only the driver
lock is held. Without this we'd have to hold the per-driver lock over
a much larger block of code which hurts concurrancy.

The QEMU driver cannot directly dispatch events, instead we have to
follow the remote driver and maintain a queue of pending events, and
use a timer to flush them. Again this is neccessary to improve
concurrency & provide safe re-entrancy.

Since we have two driver maintaining queues of evnts I add more 
helper functions to allow code sharing

 - Send a single vent to a list of callbacks:

  void virDomainEventDispatch(virDomainEventPtr event,
                              virDomainEventCallbackListPtr cbs,
                              virDomainEventDispatchFunc dispatch,
                              void *opaque);

 - Send a set of queued events to a list of callbacks

  void virDomainEventQueueDispatch(virDomainEventQueuePtr queue,
                                   virDomainEventCallbackListPtr cbs,
                                   virDomainEventDispatchFunc dispatch,
                                   void *opaque);

The virDomainEventDispatchFunc is what is invoked to finally dispatch
a single event, to a single registered callback. The default impl just
invokes the callback directly. The QEMU driver, however, uses a wrapper
which first releases its driver lock, invokes the callback, and then
re-aquires the lock.

As a further complication it is not safe for virDomainEventUnregister
to actually remove the callback from the list directly. Instead we
add a helper that simply marks it as removed, and then actually 
purge it from a safe point in the code, when its guarenteed that the
driver isn't in the middle of dispatching.

As well as making the QEMU driver thread safe, this also takes the
opportunity to refactor the Xen / remote drivers to use more helpers


 domain_event.c         |  191 +++++++++++++++++++++++----
 domain_event.h         |   51 ++++++-
 libvirt_sym.version.in |   16 ++
 qemu_conf.h            |    3 
 qemu_driver.c          |  339 +++++++++++++++++++++++++++++++------------------
 remote_internal.c      |   93 +++++--------
 xen_inotify.c          |  135 ++++++++++---------
 xen_unified.c          |   30 +---
 xen_unified.h          |    4 
 xs_internal.c          |   56 +++-----
 10 files changed, 594 insertions(+), 324 deletions(-)

Daniel

diff --git a/src/domain_event.c b/src/domain_event.c
--- a/src/domain_event.c
+++ b/src/domain_event.c
@@ -125,6 +125,49 @@ virDomainEventCallbackListRemoveConn(vir
     return 0;
 }
 
+int virDomainEventCallbackListMarkDelete(virConnectPtr conn,
+                                         virDomainEventCallbackListPtr cbList,
+                                         virConnectDomainEventCallback callback)
+{
+    int i;
+    for (i = 0 ; i < cbList->count ; i++) {
+        if (cbList->callbacks[i]->conn == conn &&
+            cbList->callbacks[i]->cb == callback) {
+            cbList->callbacks[i]->deleted = 1;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList)
+{
+    int old_count = cbList->count;
+    int i;
+    for (i = 0 ; i < cbList->count ; i++) {
+        if (cbList->callbacks[i]->deleted) {
+            virFreeCallback freecb = cbList->callbacks[i]->freecb;
+            if (freecb)
+                (*freecb)(cbList->callbacks[i]->opaque);
+            virUnrefConnect(cbList->callbacks[i]->conn);
+            VIR_FREE(cbList->callbacks[i]);
+
+            if (i < (cbList->count - 1))
+                memmove(cbList->callbacks + i,
+                        cbList->callbacks + i + 1,
+                        sizeof(*(cbList->callbacks)) *
+                                (cbList->count - (i + 1)));
+            cbList->count--;
+            i--;
+        }
+    }
+    if (cbList->count < old_count &&
+        VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) {
+        ; /* Failure to reduce memory allocation isn't fatal */
+    }
+    return 0;
+}
+
 /**
  * virDomainEventCallbackListAdd:
  * @conn: pointer to the connection
@@ -182,6 +225,62 @@ virDomainEventCallbackListAdd(virConnect
     return 0;
 }
 
+void virDomainEventFree(virDomainEventPtr event)
+{
+    if (!event)
+        return;
+
+    VIR_FREE(event->name);
+    VIR_FREE(event);
+}
+
+
+virDomainEventQueuePtr virDomainEventQueueNew(void)
+{
+    virDomainEventQueuePtr ret;
+
+    if (VIR_ALLOC(ret) < 0)
+        return NULL;
+
+    return ret;
+}
+
+virDomainEventPtr virDomainEventNew(int id, const char *name,
+                                    const unsigned char *uuid,
+                                    int type, int detail)
+{
+    virDomainEventPtr event;
+
+    if (VIR_ALLOC(event) < 0)
+        return NULL;
+
+    event->type = type;
+    event->detail = detail;
+    if (!(event->name = strdup(name))) {
+        VIR_FREE(event);
+        return NULL;
+    }
+    event->id = id;
+    memcpy(event->uuid, uuid, VIR_UUID_BUFLEN);
+
+    return event;
+}
+
+virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detail)
+{
+    return virDomainEventNew(dom->id, dom->name, dom->uuid, type, detail);
+}
+
+virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail)
+{
+    return virDomainEventNewFromDef(obj->def, type, detail);
+}
+
+virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail)
+{
+    return virDomainEventNew(def->id, def->name, def->uuid, type, detail);
+}
+
 /**
  * virDomainEventQueueFree:
  * @queue: pointer to the queue
@@ -192,14 +291,18 @@ virDomainEventQueueFree(virDomainEventQu
 virDomainEventQueueFree(virDomainEventQueuePtr queue)
 {
     int i;
-    for ( i=0 ; i<queue->count ; i++ ) {
-        VIR_FREE(queue->events[i]);
+    if (!queue)
+        return;
+
+    for (i = 0; i < queue->count ; i++) {
+        virDomainEventFree(queue->events[i]);
     }
+    VIR_FREE(queue->events);
     VIR_FREE(queue);
 }
 
 /**
- * virDomainEventCallbackQueuePop:
+ * virDomainEventQueuePop:
  * @evtQueue: the queue of events
  *
  * Internal function to pop off, and return the front of the queue
@@ -208,7 +311,7 @@ virDomainEventQueueFree(virDomainEventQu
  * Returns: virDomainEventPtr on success NULL on failure.
  */
 virDomainEventPtr
-virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue)
+virDomainEventQueuePop(virDomainEventQueuePtr evtQueue)
 {
     virDomainEventPtr ret;
 
@@ -232,9 +335,8 @@ virDomainEventCallbackQueuePop(virDomain
 }
 
 /**
- * virDomainEventCallbackQueuePush:
+ * virDomainEventQueuePush:
  * @evtQueue: the dom event queue
- * @dom: the domain to add
  * @event: the event to add
  *
  * Internal function to push onto the back of an virDomainEventQueue
@@ -242,37 +344,76 @@ virDomainEventCallbackQueuePop(virDomain
  * Returns: 0 on success, -1 on failure
  */
 int
-virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
-                                virDomainPtr dom,
-                                int event,
-                                int detail)
+virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
+                        virDomainEventPtr event)
 {
-    virDomainEventPtr domEvent;
-
-    /* Check incoming */
-    if ( !evtQueue ) {
+    if (!evtQueue) {
         return -1;
     }
-
-    /* Allocate new event */
-    if (VIR_ALLOC(domEvent) < 0) {
-        DEBUG0("Error allocating event");
-        return -1;
-    }
-    domEvent->dom = dom;
-    domEvent->event = event;
-    domEvent->detail = detail;
 
     /* Make space on queue */
     if (VIR_REALLOC_N(evtQueue->events,
                       evtQueue->count + 1) < 0) {
         DEBUG0("Error reallocating queue");
-        VIR_FREE(domEvent);
         return -1;
     }
 
-    evtQueue->events[evtQueue->count] = domEvent;
+    evtQueue->events[evtQueue->count] = event;
     evtQueue->count++;
     return 0;
 }
 
+
+void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+                                       virDomainEventPtr event,
+                                       virConnectDomainEventCallback cb,
+                                       void *cbopaque,
+                                       void *opaque ATTRIBUTE_UNUSED)
+{
+    virDomainPtr dom = virGetDomain(conn, event->name, event->uuid);
+    if (dom) {
+        dom->id = event->id;
+        (*cb)(conn, dom, event->type, event->detail, cbopaque);
+        virDomainFree(dom);
+    }
+}
+
+
+void virDomainEventDispatch(virDomainEventPtr event,
+                            virDomainEventCallbackListPtr callbacks,
+                            virDomainEventDispatchFunc dispatch,
+                            void *opaque)
+{
+    int i;
+    /* Cache this now, since we may be dropping the lock,
+       and have more callbacks added. We're guarenteed not
+       to have any removed */
+    int cbCount = callbacks->count;
+
+    for (i = 0 ; i < cbCount ; i++) {
+        if (callbacks->callbacks[i] &&
+            !callbacks->callbacks[i]->deleted) {
+            (*dispatch)(callbacks->callbacks[i]->conn,
+                        event,
+                        callbacks->callbacks[i]->cb,
+                        callbacks->callbacks[i]->opaque,
+                        opaque);
+        }
+    }
+}
+
+
+void virDomainEventQueueDispatch(virDomainEventQueuePtr queue,
+                                 virDomainEventCallbackListPtr callbacks,
+                                 virDomainEventDispatchFunc dispatch,
+                                 void *opaque)
+{
+    int i;
+
+    for (i = 0 ; i < queue->count ; i++) {
+        virDomainEventDispatch(queue->events[i], callbacks, dispatch, opaque);
+        virDomainEventFree(queue->events[i]);
+    }
+    VIR_FREE(queue->events);
+    queue->count = 0;
+}
diff --git a/src/domain_event.h b/src/domain_event.h
--- a/src/domain_event.h
+++ b/src/domain_event.h
@@ -22,16 +22,17 @@
 
 #include "internal.h"
 
-
 #ifndef __DOMAIN_EVENT_H__
 #define __DOMAIN_EVENT_H__
+
+#include "domain_conf.h"
 
 struct _virDomainEventCallback {
     virConnectPtr conn;
     virConnectDomainEventCallback cb;
     void *opaque;
     virFreeCallback freecb;
-
+    int deleted;
 };
 typedef struct _virDomainEventCallback virDomainEventCallback;
 typedef virDomainEventCallback *virDomainEventCallbackPtr;
@@ -58,13 +59,20 @@ int virDomainEventCallbackListRemoveConn
 int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
                                          virDomainEventCallbackListPtr cbList);
 
+int virDomainEventCallbackListMarkDelete(virConnectPtr conn,
+                                         virDomainEventCallbackListPtr cbList,
+                                         virConnectDomainEventCallback callback);
+int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList);
+
 /**
  * Dispatching domain events that come in while
  * in a call / response rpc
  */
 struct _virDomainEvent {
-    virDomainPtr dom;
-    int event;
+    int id;
+    char *name;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    int type;
     int detail;
 };
 typedef struct _virDomainEvent virDomainEvent;
@@ -77,15 +85,40 @@ typedef struct _virDomainEventQueue virD
 typedef struct _virDomainEventQueue virDomainEventQueue;
 typedef virDomainEventQueue *virDomainEventQueuePtr;
 
-int virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
-                                    virDomainPtr dom,
-                                    int event,
-                                    int detail);
+virDomainEventQueuePtr virDomainEventQueueNew(void);
+
+virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail);
+virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detail);
+virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail);
+virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail);
+
+int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
+                            virDomainEventPtr event);
 
 virDomainEventPtr
-virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue);
+virDomainEventQueuePop(virDomainEventQueuePtr evtQueue);
 
+void virDomainEventFree(virDomainEventPtr event);
 void virDomainEventQueueFree(virDomainEventQueuePtr queue);
 
+typedef void (*virDomainEventDispatchFunc)(virConnectPtr conn,
+                                           virDomainEventPtr event,
+                                           virConnectDomainEventCallback cb,
+                                           void *cbopaque,
+                                           void *opaque);
+void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+                                       virDomainEventPtr event,
+                                       virConnectDomainEventCallback cb,
+                                       void *cbopaque,
+                                       void *opaque);
+
+void virDomainEventDispatch(virDomainEventPtr event,
+                            virDomainEventCallbackListPtr cbs,
+                            virDomainEventDispatchFunc dispatch,
+                            void *opaque);
+void virDomainEventQueueDispatch(virDomainEventQueuePtr queue,
+                                 virDomainEventCallbackListPtr cbs,
+                                 virDomainEventDispatchFunc dispatch,
+                                 void *opaque);
 
 #endif
diff --git a/src/libvirt_sym.version.in b/src/libvirt_sym.version.in
--- a/src/libvirt_sym.version.in
+++ b/src/libvirt_sym.version.in
@@ -382,9 +382,21 @@ LIBVIRT_PRIVATE_ at VERSION@ {
 	virDomainEventCallbackListFree;
 	virDomainEventCallbackListRemove;
 	virDomainEventCallbackListRemoveConn;
+	virDomainEventCallbackListMarkDelete;
+	virDomainEventCallbackListPurgeMarked;
+	virDomainEventQueueNew;
 	virDomainEventQueueFree;
-	virDomainEventCallbackQueuePop;
-	virDomainEventCallbackQueuePush;
+	virDomainEventQueuePop;
+	virDomainEventQueuePush;
+	virDomainEventNew;
+	virDomainEventNewFromDom;
+	virDomainEventNewFromObj;
+	virDomainEventNewFromDef;
+	virDomainEventFree;
+	virDomainEventDispatchDefaultFunc;
+	virDomainEventDispatch;
+	virDomainEventQueueDispatch;
+
 
 
 	/* driver.h */
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -71,6 +71,9 @@ struct qemud_driver {
 
     /* An array of callbacks */
     virDomainEventCallbackListPtr domainEventCallbacks;
+    virDomainEventQueuePtr domainEventQueue;
+    int domainEventTimer;
+    int domainEventDispatching;
 };
 
 /* Port numbers used for KVM migration. */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -115,10 +115,10 @@ static int qemudSetNonBlock(int fd) {
 }
 
 
-static void qemudDomainEventDispatch (struct qemud_driver *driver,
-                                      virDomainObjPtr vm,
-                                      int event,
-                                      int detail);
+
+static void qemuDomainEventFlush(int timer, void *opaque);
+static void qemuDomainEventQueue(struct qemud_driver *driver,
+                                 virDomainEventPtr event);
 
 static void qemudDispatchVMEvent(int watch,
                                  int fd,
@@ -160,8 +160,12 @@ qemudAutostartConfigs(struct qemud_drive
                          vm->def->name,
                          err ? err->message : NULL);
             } else {
-                qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED,
-                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
+                virDomainEventPtr event =
+                    virDomainEventNewFromObj(vm,
+                                             VIR_DOMAIN_EVENT_STARTED,
+                                             VIR_DOMAIN_EVENT_STARTED_BOOTED);
+                if (event)
+                    qemuDomainEventQueue(driver, event);
             }
         }
         virDomainObjUnlock(vm);
@@ -192,6 +196,12 @@ qemudStartup(void) {
     /* Init callback list */
     if(VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
         goto out_of_memory;
+    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
+        goto out_of_memory;
+
+    if ((qemu_driver->domainEventTimer =
+         virEventAddTimeout(-1, qemuDomainEventFlush, qemu_driver, NULL)) < 0)
+        goto error;
 
     if (!uid) {
         if (asprintf(&qemu_driver->logDir,
@@ -266,10 +276,14 @@ static void qemudNotifyLoadDomain(virDom
 {
     struct qemud_driver *driver = opaque;
 
-    if (newVM)
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_DEFINED,
-                                 VIR_DOMAIN_EVENT_DEFINED_ADDED);
+    if (newVM) {
+        virDomainEventPtr event =
+            virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_DEFINED,
+                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
+        if (event)
+            qemuDomainEventQueue(driver, event);
+    }
 }
 
 /**
@@ -356,6 +370,10 @@ qemudShutdown(void) {
 
     /* Free domain callback list */
     virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
+    virDomainEventQueueFree(qemu_driver->domainEventQueue);
+
+    if (qemu_driver->domainEventTimer != -1)
+        virEventRemoveTimeout(qemu_driver->domainEventTimer);
 
     if (qemu_driver->brctl)
         brShutdown(qemu_driver->brctl);
@@ -1073,6 +1091,7 @@ qemudDispatchVMEvent(int watch, int fd, 
 qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
     struct qemud_driver *driver = opaque;
     virDomainObjPtr vm = NULL;
+    virDomainEventPtr event = NULL;
     unsigned int i;
     int quit = 0, failed = 0;
 
@@ -1102,12 +1121,12 @@ qemudDispatchVMEvent(int watch, int fd, 
     }
 
     if (failed || quit) {
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         quit ?
+                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
+                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
         qemudShutdownVMDaemon(NULL, driver, vm);
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_STOPPED,
-                                 quit ?
-                                 VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
-                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
         if (!vm->persistent) {
             virDomainRemoveInactive(&driver->domains,
                                     vm);
@@ -1118,6 +1137,8 @@ cleanup:
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
 }
 
@@ -1585,6 +1606,7 @@ static virDomainPtr qemudDomainCreate(vi
     virDomainDefPtr def;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     if (!(def = virDomainDefParseString(conn, driver->caps, xml)))
@@ -1621,9 +1643,10 @@ static virDomainPtr qemudDomainCreate(vi
         vm = NULL;
         goto cleanup;
     }
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STARTED,
-                             VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
 
     dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
     if (dom) dom->id = vm->def->id;
@@ -1632,6 +1655,8 @@ cleanup:
     virDomainDefFree(def);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return dom;
 }
@@ -1642,6 +1667,7 @@ static int qemudDomainSuspend(virDomainP
     char *info;
     virDomainObjPtr vm;
     int ret = -1;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     vm = virDomainFindByID(&driver->domains, dom->id);
@@ -1664,16 +1690,22 @@ static int qemudDomainSuspend(virDomainP
         }
         vm->state = VIR_DOMAIN_PAUSED;
         qemudDebug("Reply %s", info);
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_SUSPENDED,
-                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
-        VIR_FREE(info);
-    }
-    ret = 0;
-
-cleanup:
-    if (vm)
-        virDomainObjUnlock(vm);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_SUSPENDED,
+                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+        VIR_FREE(info);
+    }
+    ret = 0;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+
+    if (event) {
+        qemuDriverLock(driver);
+        qemuDomainEventQueue(driver, event);
+        qemuDriverUnlock(driver);
+    }
     return ret;
 }
 
@@ -1683,6 +1715,7 @@ static int qemudDomainResume(virDomainPt
     char *info;
     virDomainObjPtr vm;
     int ret = -1;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     vm = virDomainFindByID(&driver->domains, dom->id);
@@ -1706,16 +1739,21 @@ static int qemudDomainResume(virDomainPt
         }
         vm->state = VIR_DOMAIN_RUNNING;
         qemudDebug("Reply %s", info);
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_RESUMED,
-                                 VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
-        VIR_FREE(info);
-    }
-    ret = 0;
-
-cleanup:
-    if (vm)
-        virDomainObjUnlock(vm);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_RESUMED,
+                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+        VIR_FREE(info);
+    }
+    ret = 0;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    if (event) {
+        qemuDriverLock(driver);
+        qemuDomainEventQueue(driver, event);
+        qemuDriverUnlock(driver);
+    }
     return ret;
 }
 
@@ -1755,6 +1793,7 @@ static int qemudDomainDestroy(virDomainP
     struct qemud_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
     int ret = -1;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     vm  = virDomainFindByID(&driver->domains, dom->id);
@@ -1765,9 +1804,9 @@ static int qemudDomainDestroy(virDomainP
     }
 
     qemudShutdownVMDaemon(dom->conn, driver, vm);
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STOPPED,
-                             VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -1778,6 +1817,8 @@ cleanup:
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -2047,6 +2088,7 @@ static int qemudDomainSave(virDomainPtr 
     char *xml = NULL;
     struct qemud_save_header header;
     int ret = -1;
+    virDomainEventPtr event = NULL;
 
     memset(&header, 0, sizeof(header));
     memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
@@ -2148,9 +2190,9 @@ static int qemudDomainSave(virDomainPtr 
 
     /* Shut it down */
     qemudShutdownVMDaemon(dom->conn, driver, vm);
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STOPPED,
-                             VIR_DOMAIN_EVENT_STOPPED_SAVED);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -2169,6 +2211,8 @@ cleanup:
         unlink(path);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -2406,6 +2450,7 @@ static int qemudDomainRestore(virConnect
     int ret = -1;
     char *xml = NULL;
     struct qemud_save_header header;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     /* Verify the header and read the XML */
@@ -2489,9 +2534,9 @@ static int qemudDomainRestore(virConnect
         goto cleanup;
     }
 
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STARTED,
-                             VIR_DOMAIN_EVENT_STARTED_RESTORED);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
 
     /* If it was running before, resume it now. */
     if (header.was_running) {
@@ -2513,6 +2558,8 @@ cleanup:
         close(fd);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -2593,6 +2640,7 @@ static int qemudDomainStart(virDomainPtr
     struct qemud_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
     int ret = -1;
+    virDomainEventPtr event = NULL;
 
     qemuDriverLock(driver);
     vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -2606,13 +2654,18 @@ static int qemudDomainStart(virDomainPtr
 
     ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL);
     if (ret != -1)
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_STARTED,
-                                 VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
-cleanup:
-    if (vm)
-        virDomainObjUnlock(vm);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STARTED,
+                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    if (event) {
+        qemuDriverLock(driver);
+        qemuDomainEventQueue(driver, event);
+        qemuDriverUnlock(driver);
+    }
     return ret;
 }
 
@@ -2622,6 +2675,7 @@ static virDomainPtr qemudDomainDefine(vi
     virDomainDefPtr def;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
+    virDomainEventPtr event = NULL;
     int newVM = 1;
 
     qemuDriverLock(driver);
@@ -2651,18 +2705,20 @@ static virDomainPtr qemudDomainDefine(vi
         goto cleanup;
     }
 
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_DEFINED,
-                             newVM ?
-                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
-                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
-
-    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
-    if (dom) dom->id = vm->def->id;
-
-cleanup:
-    if (vm)
-        virDomainObjUnlock(vm);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_DEFINED,
+                                     newVM ?
+                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
+                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+
+    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+    if (dom) dom->id = vm->def->id;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return dom;
 }
@@ -2670,6 +2726,7 @@ static int qemudDomainUndefine(virDomain
 static int qemudDomainUndefine(virDomainPtr dom) {
     struct qemud_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     int ret = -1;
 
     qemuDriverLock(driver);
@@ -2696,9 +2753,9 @@ static int qemudDomainUndefine(virDomain
     if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) < 0)
         goto cleanup;
 
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_UNDEFINED,
-                             VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_UNDEFINED,
+                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
 
     virDomainRemoveInactive(&driver->domains,
                             vm);
@@ -2708,6 +2765,8 @@ cleanup:
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -3703,41 +3762,69 @@ qemudDomainEventDeregister (virConnectPt
     int ret;
 
     qemuDriverLock(driver);
-    ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
-                                           callback);
-    qemuDriverUnlock(driver);
-
-    return ret;
-}
-
-static void qemudDomainEventDispatch (struct qemud_driver *driver,
-                                      virDomainObjPtr vm,
-                                      int event,
-                                      int detail)
-{
-    int i;
-    virDomainEventCallbackListPtr cbList;
-
-    cbList = driver->domainEventCallbacks;
-
-    for(i=0 ; i < cbList->count ; i++) {
-        if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
-            virConnectPtr conn = cbList->callbacks[i]->conn;
-            virDomainPtr dom = virGetDomain(conn, vm->def->name,
-                                            vm->def->uuid);
-            if (dom) {
-                dom->id = virDomainIsActive(vm) ? vm->def->id : -1;
-                DEBUG("Dispatching callback %p %p event %d detail %d",
-                      cbList->callbacks[i],
-                      cbList->callbacks[i]->cb, event, detail);
-                cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
-                                         dom, event, detail,
-                                         cbList->callbacks[i]->opaque);
-                virDomainFree(dom);
-            }
-        }
-    }
-
+    if (driver->domainEventDispatching)
+        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
+                                                   callback);
+    else
+        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
+                                               callback);
+    qemuDriverUnlock(driver);
+
+    return ret;
+}
+
+static void qemuDomainEventDispatchFunc(virConnectPtr conn,
+                                        virDomainEventPtr event,
+                                        virConnectDomainEventCallback cb,
+                                        void *cbopaque,
+                                        void *opaque)
+{
+    struct qemud_driver *driver = opaque;
+
+    /* Drop the lock whle dispatching, for sake of re-entrancy */
+    qemuDriverUnlock(driver);
+    virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
+    qemuDriverLock(driver);
+}
+
+static void qemuDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
+{
+    struct qemud_driver *driver = opaque;
+    virDomainEventQueue tempQueue;
+
+    qemuDriverLock(driver);
+
+    driver->domainEventDispatching = 1;
+
+    /* Copy the queue, so we're reentrant safe */
+    tempQueue.count = driver->domainEventQueue->count;
+    tempQueue.events = driver->domainEventQueue->events;
+    driver->domainEventQueue->count = 0;
+    driver->domainEventQueue->events = NULL;
+
+    virEventUpdateTimeout(driver->domainEventTimer, -1);
+    virDomainEventQueueDispatch(&tempQueue,
+                                driver->domainEventCallbacks,
+                                qemuDomainEventDispatchFunc,
+                                driver);
+
+    /* Purge any deleted callbacks */
+    virDomainEventCallbackListPurgeMarked(driver->domainEventCallbacks);
+
+    driver->domainEventDispatching = 0;
+    qemuDriverUnlock(driver);
+}
+
+
+/* driver must be locked before calling */
+static void qemuDomainEventQueue(struct qemud_driver *driver,
+                                 virDomainEventPtr event)
+{
+    if (virDomainEventQueuePush(driver->domainEventQueue,
+                                event) < 0)
+        virDomainEventFree(event);
+    if (qemu_driver->domainEventQueue->count == 1)
+        virEventUpdateTimeout(driver->domainEventTimer, 0);
 }
 
 /* Migration support. */
@@ -3765,6 +3852,7 @@ qemudDomainMigratePrepare2 (virConnectPt
     char hostname [HOST_NAME_MAX+1];
     char migrateFrom [64];
     const char *p;
+    virDomainEventPtr event = NULL;
     int ret = -1;;
 
     *uri_out = NULL;
@@ -3886,9 +3974,10 @@ qemudDomainMigratePrepare2 (virConnectPt
         }
         goto cleanup;
     }
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STARTED,
-                             VIR_DOMAIN_EVENT_STARTED_MIGRATED);
+
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STARTED,
+                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
     ret = 0;
 
 cleanup:
@@ -3898,6 +3987,8 @@ cleanup:
     }
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -3914,6 +4005,7 @@ qemudDomainMigratePerform (virDomainPtr 
 {
     struct qemud_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     char *safe_uri;
     char cmd[HOST_NAME_MAX+50];
     char *info = NULL;
@@ -3940,9 +4032,12 @@ qemudDomainMigratePerform (virDomainPtr 
         DEBUG ("stop reply: %s", info);
         VIR_FREE(info);
 
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_SUSPENDED,
-                                 VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_SUSPENDED,
+                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+        if (event)
+            qemuDomainEventQueue(driver, event);
+        event = NULL;
     }
 
     if (resource > 0) {
@@ -3981,9 +4076,10 @@ qemudDomainMigratePerform (virDomainPtr 
 
     /* Clean up the source domain. */
     qemudShutdownVMDaemon (dom->conn, driver, vm);
-    qemudDomainEventDispatch(driver, vm,
-                             VIR_DOMAIN_EVENT_STOPPED,
-                             VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
+
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains, vm);
         vm = NULL;
@@ -3994,6 +4090,8 @@ cleanup:
     VIR_FREE(info);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return ret;
 }
@@ -4011,6 +4109,7 @@ qemudDomainMigrateFinish2 (virConnectPtr
     struct qemud_driver *driver = dconn->privateData;
     virDomainObjPtr vm;
     virDomainPtr dom = NULL;
+    virDomainEventPtr event = NULL;
     char *info = NULL;
 
     qemuDriverLock(driver);
@@ -4028,14 +4127,14 @@ qemudDomainMigrateFinish2 (virConnectPtr
         dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
         VIR_FREE(info);
         vm->state = VIR_DOMAIN_RUNNING;
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_RESUMED,
-                                 VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_RESUMED,
+                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
     } else {
         qemudShutdownVMDaemon (dconn, driver, vm);
-        qemudDomainEventDispatch(driver, vm,
-                                 VIR_DOMAIN_EVENT_STOPPED,
-                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
         if (!vm->persistent) {
             virDomainRemoveInactive(&driver->domains, vm);
             vm = NULL;
@@ -4045,6 +4144,8 @@ cleanup:
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
     qemuDriverUnlock(driver);
     return dom;
 }
diff --git a/src/remote_internal.c b/src/remote_internal.c
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -5484,59 +5484,62 @@ remoteRegister (void)
  *
  * Read the event data off the wire
  */
-static int
-remoteDomainReadEvent(virConnectPtr conn, XDR *xdr,
-                      virDomainPtr *dom, int *event, int *detail)
+static virDomainEventPtr
+remoteDomainReadEvent(virConnectPtr conn, XDR *xdr)
 {
     remote_domain_event_ret ret;
+    virDomainPtr dom;
+    virDomainEventPtr event = NULL;
     memset (&ret, 0, sizeof ret);
 
     /* unmarshall parameters, and process it*/
     if (! xdr_remote_domain_event_ret(xdr, &ret) ) {
         error (conn, VIR_ERR_RPC,
                _("remoteDomainProcessEvent: unmarshalling ret"));
-        return -1;
-    }
-
-    *dom = get_nonnull_domain(conn,ret.dom);
-    *event = ret.event;
-    *detail = ret.detail;
-
-    return 0;
+        return NULL;
+    }
+
+    dom = get_nonnull_domain(conn,ret.dom);
+    if (!dom)
+        return NULL;
+
+    event = virDomainEventNewFromDom(dom, ret.event, ret.detail);
+
+    virDomainFree(dom);
+    return event;
 }
 
 static void
 remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr)
 {
-    virDomainPtr dom;
-    int event, detail, i;
-    struct private_data *priv = conn->privateData;
-
-    if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail)) {
-        DEBUG0("Calling domain event callbacks (no queue)");
-        for(i=0 ; i < priv->callbackList->count ; i++) {
-            if (priv->callbackList->callbacks[i] )
-                priv->callbackList->callbacks[i]->cb(
-                    conn, dom, event, detail,
-                    priv->callbackList->callbacks[i]->opaque);
-        }
-    }
+    struct private_data *priv = conn->privateData;
+    virDomainEventPtr event;
+
+    event = remoteDomainReadEvent(conn, xdr);
+    if (!event)
+        return;
+
+    DEBUG0("Calling domain event callbacks (no queue)");
+    virDomainEventDispatch(event, priv->callbackList,
+                           virDomainEventDispatchDefaultFunc, NULL);
+    virDomainEventFree(event);
 }
 
 static void
 remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr)
 {
-    virDomainPtr dom;
-    int event, detail;
-    struct private_data *priv = conn->privateData;
-
-    if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail))
-    {
-        if( virDomainEventCallbackQueuePush(priv->domainEvents,
-                                            dom, event, detail) < 0 ) {
-            DEBUG("%s", "Error adding event to queue");
-        }
-    }
+    struct private_data *priv = conn->privateData;
+    virDomainEventPtr event;
+
+    event = remoteDomainReadEvent(conn, xdr);
+    if (!event)
+        return;
+
+    if (virDomainEventQueuePush(priv->domainEvents,
+                                event) < 0)
+        DEBUG0("Error adding event to queue");
+
+    virDomainEventFree(event);
 }
 
 /** remoteDomainEventFired:
@@ -5618,26 +5621,10 @@ void
 void
 remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
 {
-    int i;
-    virDomainEventPtr domEvent;
-    void *user_data = NULL;
     virConnectPtr conn = opaque;
     struct private_data *priv = conn->privateData;
 
-    while( (domEvent = virDomainEventCallbackQueuePop(priv->domainEvents)) ) {
-        DEBUG("   Flushing %p", domEvent);
-        for (i=0 ; i < priv->callbackList->count ; i++) {
-           if( priv->callbackList->callbacks[i] ) {
-               user_data = priv->callbackList->callbacks[i]->opaque;
-               priv->callbackList->callbacks[i]->cb(domEvent->dom->conn,
-                                                    domEvent->dom,
-                                                    domEvent->event,
-                                                    domEvent->detail,
-                                                    user_data);
-           }
-        }
-        VIR_FREE(domEvent);
-    }
-
+    virDomainEventQueueDispatch(priv->domainEvents, priv->callbackList,
+                                virDomainEventDispatchDefaultFunc, NULL);
     virEventUpdateTimeout(priv->eventFlushTimer, -1);
 }
diff --git a/src/xen_inotify.c b/src/xen_inotify.c
--- a/src/xen_inotify.c
+++ b/src/xen_inotify.c
@@ -92,30 +92,33 @@ struct xenUnifiedDriver xenInotifyDriver
     NULL, /* domainSetSchedulerParameters */
 };
 
-static virDomainPtr
-xenInotifyXenCacheLookup(virConnectPtr conn, const char *filename) {
+static int
+xenInotifyXenCacheLookup(const char *filename,
+                         char **name, unsigned char *uuid) {
     xenXMConfCachePtr entry;
-    virDomainPtr dom;
 
     if (!(entry = virHashLookup(xenXMGetConfigCache(), filename))) {
         DEBUG("No config found for %s", filename);
-        return NULL;
+        return -1;
     }
 
-    if(!(dom = virGetDomain(conn, entry->def->name,
-                    (unsigned char*)entry->def->uuid))) {
+    *name = strdup(entry->def->name);
+    memcpy(uuid, entry->def->uuid, VIR_UUID_BUFLEN);
+
+    if (!*name) {
         DEBUG0("Error getting dom from def");
-        return NULL;
+        return -1;
     }
-    return dom;
+    return 0;
 }
 
-static virDomainPtr
-xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename) {
+static int
+xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename,
+                               char **name, unsigned char *uuid) {
     int i;
     virDomainPtr dom;
     const char *uuid_str;
-    unsigned char uuid[VIR_UUID_BUFLEN];
+    unsigned char rawuuid[VIR_UUID_BUFLEN];
 
     /* xend is managing domains. we will get
     * a filename in the manner:
@@ -123,57 +126,70 @@ xenInotifyXendDomainsDirLookup(virConnec
     */
     uuid_str = filename + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
 
-    if (virUUIDParse(uuid_str, uuid) < 0) {
+    if (virUUIDParse(uuid_str, rawuuid) < 0) {
         virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
                            "parsing uuid %s", uuid_str);
-        return (NULL);
+        return -1;
     }
     /* call directly into xend here, as driver may not yet
        be set during open while we are building our
        initial list of domains */
     DEBUG("Looking for dom with uuid: %s", uuid_str);
-    if(!(dom = xenDaemonLookupByUUID(conn, uuid))) {
+    /* XXX Should not have to go via a virDomainPtr obj instance */
+    if(!(dom = xenDaemonLookupByUUID(conn, rawuuid))) {
         /* If we are here, the domain has gone away.
            search for, and create a domain from the stored
            list info */
         for (i=0; i<configInfoList->count; i++) {
             if (!memcmp(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
-                if(!(dom = virGetDomain(conn, configInfoList->doms[i]->name,
-                                        configInfoList->doms[i]->uuid))) {
+                *name = strdup(configInfoList->doms[i]->name);
+                if (!*name) {
                     virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
                                        "finding dom for %s", uuid_str);
-                    return NULL;
+                    return -1;
                 }
+                memcpy(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN);
                 DEBUG0("Found dom on list");
-                return dom;
+                return 0;
             }
         }
         virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
-                                       "%s", _("finding dom on config list"));
-        return NULL;
+                           "%s", _("finding dom on config list"));
+        return -1;
     }
 
+    if (!(*name = strdup(dom->name)))
+        return -1;
+    memcpy(uuid, dom->uuid, VIR_UUID_BUFLEN);
+    virDomainFree(dom);
     /* succeeded too find domain by uuid */
-    return dom;
+    return 0;
 }
 
-static virDomainPtr
-xenInotifyDomainLookup(virConnectPtr conn, const char *filename) {
-    virDomainPtr dom;
-    virDomainInfo info;
+static int
+xenInotifyDomainLookup(virConnectPtr conn,
+                       const char *filename,
+                       char **name, unsigned char *uuid) {
+    if (useXenConfigCache)
+        return xenInotifyXenCacheLookup(filename, name, uuid);
+    else
+        return xenInotifyXendDomainsDirLookup(conn, filename, name, uuid);
+}
 
-    dom = useXenConfigCache ? xenInotifyXenCacheLookup(conn, filename) :
-                              xenInotifyXendDomainsDirLookup(conn, filename);
+static virDomainEventPtr
+xenInotifyDomainEventFromFile(virConnectPtr conn,
+                              const char *filename,
+                              int type, int detail) {
+    virDomainEventPtr event;
+    char *name = NULL;
+    unsigned char uuid[VIR_UUID_BUFLEN];
 
-    if(dom) {
-        if ( (useXenConfigCache ? xenXMDomainGetInfo(dom, &info) :
-                                  xenDaemonDomainGetInfo(dom, &info)) < 0)
-            dom->id = -1;
-        else
-            dom->id = (info.state == VIR_DOMAIN_SHUTOFF) ? -1 : dom->id;
-        return dom;
-    }
-    return NULL;
+    if (xenInotifyDomainLookup(conn, filename, &name, uuid) < 0)
+        return NULL;
+
+    event = virDomainEventNew(-1, name, uuid, type, detail);
+    VIR_FREE(name);
+    return event;
 }
 
 static int
@@ -215,21 +231,22 @@ static int
 static int
 xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
                                  const char *fname) {
-    virDomainPtr dom = xenInotifyDomainLookup(conn, fname);
-    if(!dom) {
+    char *name = NULL;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    if (xenInotifyDomainLookup(conn, fname, &name, uuid) < 0) {
         virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("Error looking up domain"));
+                           "%s", _("Error looking up domain"));
         return -1;
     }
 
     if( xenUnifiedAddDomainInfo(configInfoList,
-                                dom->id, dom->name, dom->uuid) < 0) {
+                                -1, name, uuid) < 0) {
         virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Error adding file to config cache"));
-        virUnrefDomain(dom);
+        VIR_FREE(name);
         return -1;
     }
-    virUnrefDomain(dom);
+    VIR_FREE(name);
     return 0;
 }
 
@@ -260,7 +277,6 @@ xenInotifyEvent(int watch ATTRIBUTE_UNUS
     char *tmp, *name;
     virConnectPtr conn = (virConnectPtr) data;
     xenUnifiedPrivatePtr priv = NULL;
-    virDomainPtr dom = NULL;
 
     DEBUG0("got inotify event");
 
@@ -300,16 +316,15 @@ reread:
         snprintf(fname, 1024, "%s/%s", configDir, name);
 
         if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
-            if (!(dom = xenInotifyDomainLookup(conn, fname))) {
+            virDomainEventPtr event =
+                xenInotifyDomainEventFromFile(conn, fname,
+                                              VIR_DOMAIN_EVENT_UNDEFINED,
+                                              VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+            if (!event)
+                xenUnifiedDomainEventDispatch(conn->privateData, event);
+            else
                 virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
-                           "%s", _("looking up dom"));
-                continue;
-            }
-
-            xenUnifiedDomainEventDispatch(conn->privateData, dom,
-                                          VIR_DOMAIN_EVENT_UNDEFINED,
-                                          VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
-
+                                   "%s", _("looking up dom"));
 
             if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
                 virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
@@ -317,21 +332,23 @@ reread:
                 return;
             }
         } else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
+            virDomainEventPtr event;
             if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
                 virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Error adding file to config cache"));
                 return;
             }
 
-            if (!(dom = xenInotifyDomainLookup(conn, fname))) {
+            event = xenInotifyDomainEventFromFile(conn, fname,
+                                                  VIR_DOMAIN_EVENT_DEFINED,
+                                                  VIR_DOMAIN_EVENT_DEFINED_ADDED);
+
+            if (event)
+                xenUnifiedDomainEventDispatch(conn->privateData, event);
+            else
                 virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
-                           "%s", _("looking up dom"));
-                continue;
-            }
+                                   "%s", _("looking up dom"));
 
-            xenUnifiedDomainEventDispatch(conn->privateData, dom,
-                                          VIR_DOMAIN_EVENT_DEFINED,
-                                          VIR_DOMAIN_EVENT_DEFINED_ADDED);
         }
 
     }
diff --git a/src/xen_unified.c b/src/xen_unified.c
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -1583,28 +1583,14 @@ xenUnifiedRemoveDomainInfo(xenUnifiedDom
  *
  */
 void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
-                                    virDomainPtr dom,
-                                    int event,
-                                    int detail)
+                                    virDomainEventPtr event)
 {
-    int i;
-    virDomainEventCallbackListPtr cbList;
+    if (!priv || !priv->domainEventCallbacks)
+        return;
 
-    if(!priv) return;
-
-    cbList = priv->domainEventCallbacks;
-    if(!cbList) return;
-
-    for(i=0 ; i < cbList->count ; i++) {
-        if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
-            if (dom) {
-                DEBUG("Dispatching callback %p %p event %d",
-                        cbList->callbacks[i],
-                        cbList->callbacks[i]->cb, event);
-                cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
-                                         dom, event, detail,
-                                         cbList->callbacks[i]->opaque);
-            }
-        }
-    }
+    virDomainEventDispatch(event,
+                           priv->domainEventCallbacks,
+                           virDomainEventDispatchDefaultFunc,
+                           NULL);
+    virDomainEventFree(event);
 }
diff --git a/src/xen_unified.h b/src/xen_unified.h
--- a/src/xen_unified.h
+++ b/src/xen_unified.h
@@ -182,9 +182,7 @@ int  xenUnifiedRemoveDomainInfo(xenUnifi
                                 int id, char *name,
                                 unsigned char *uuid);
 void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
-                                    virDomainPtr dom,
-                                    int event,
-                                    int detail);
+                                    virDomainEventPtr event);
 unsigned long xenUnifiedVersion(void);
 
 #endif /* __VIR_XEN_UNIFIED_H__ */
diff --git a/src/xs_internal.c b/src/xs_internal.c
--- a/src/xs_internal.c
+++ b/src/xs_internal.c
@@ -1215,7 +1215,7 @@ retry:
         }
 
         if (!found) {
-            virDomainPtr dom;
+            virDomainEventPtr event;
             char *name;
             unsigned char uuid[VIR_UUID_BUFLEN];
 
@@ -1229,21 +1229,15 @@ retry:
                 continue;
             }
 
-            dom = virGetDomain(conn, name, uuid);
-            if (dom) {
-                dom->id = new_domids[i];
+            event = virDomainEventNew(new_domids[i], name, uuid,
+                                      VIR_DOMAIN_EVENT_STARTED,
+                                      VIR_DOMAIN_EVENT_STARTED_BOOTED);
+            if (event)
+                xenUnifiedDomainEventDispatch(priv, event);
 
-                /* This domain was not in the old list. Emit an event */
-                xenUnifiedDomainEventDispatch(priv, dom,
-                                              VIR_DOMAIN_EVENT_STARTED,
-                                              VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
-                /* Add to the list */
-                xenUnifiedAddDomainInfo(activeDomainList,
-                                        new_domids[i], name, uuid);
-
-                virUnrefDomain(dom);
-            }
+            /* Add to the list */
+            xenUnifiedAddDomainInfo(activeDomainList,
+                                    new_domids[i], name, uuid);
 
             VIR_FREE(name);
         }
@@ -1299,24 +1293,22 @@ retry:
         }
 
         if (!found) {
-            virDomainPtr dom = virGetDomain(conn,
-                                            activeDomainList->doms[j]->name,
-                                            activeDomainList->doms[j]->uuid);
-            if(dom) {
-                dom->id = -1;
-                /* This domain was not in the new list. Emit an event */
-                xenUnifiedDomainEventDispatch(priv, dom,
-                                              VIR_DOMAIN_EVENT_STOPPED,
-                                              VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-                 /* Remove from the list */
-                xenUnifiedRemoveDomainInfo(activeDomainList,
-                                           activeDomainList->doms[j]->id,
-                                           activeDomainList->doms[j]->name,
-                                           activeDomainList->doms[j]->uuid);
+            virDomainEventPtr event =
+                virDomainEventNew(-1,
+                                  activeDomainList->doms[j]->name,
+                                  activeDomainList->doms[j]->uuid,
+                                  VIR_DOMAIN_EVENT_STOPPED,
+                                  VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+            if (event)
+                xenUnifiedDomainEventDispatch(priv, event);
 
-                virUnrefDomain(dom);
-                removed = 1;
-            }
+            /* Remove from the list */
+            xenUnifiedRemoveDomainInfo(activeDomainList,
+                                       activeDomainList->doms[j]->id,
+                                       activeDomainList->doms[j]->name,
+                                       activeDomainList->doms[j]->uuid);
+
+            removed = 1;
         }
     }
 

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list