[libvirt] [PATCH 1/2] Add domain events support to LXC driver

Daniel P. Berrange berrange at redhat.com
Wed Jul 22 16:02:55 UTC 2009


* src/lxc_conf.h: Add queue for dispatch of domain events
* src/lxc_driver.c: Trigger domain events upon important lifecycle transitions

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/lxc_conf.h   |    7 ++
 src/lxc_driver.c |  181 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 185 insertions(+), 3 deletions(-)

diff --git a/src/lxc_conf.h b/src/lxc_conf.h
index 30a51e1..9690cc8 100644
--- a/src/lxc_conf.h
+++ b/src/lxc_conf.h
@@ -28,6 +28,7 @@
 
 #include "internal.h"
 #include "domain_conf.h"
+#include "domain_event.h"
 #include "capabilities.h"
 #include "threads.h"
 
@@ -47,6 +48,12 @@ struct __lxc_driver {
     char *stateDir;
     char *logDir;
     int have_netns;
+
+    /* An array of callbacks */
+    virDomainEventCallbackListPtr domainEventCallbacks;
+    virDomainEventQueuePtr domainEventQueue;
+    int domainEventTimer;
+    int domainEventDispatching;
 };
 
 int lxcLoadDriverConfig(lxc_driver_t *driver);
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
index 3503573..1b5c86c 100644
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -67,6 +67,10 @@ static void lxcDriverUnlock(lxc_driver_t *driver)
     virMutexUnlock(&driver->lock);
 }
 
+static void lxcDomainEventFlush(int timer, void *opaque);
+static void lxcDomainEventQueue(lxc_driver_t *driver,
+                                virDomainEventPtr event);
+
 
 static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
@@ -114,6 +118,12 @@ static virDrvOpenStatus lxcOpen(virConnectPtr conn,
 
 static int lxcClose(virConnectPtr conn)
 {
+    lxc_driver_t *driver = conn->privateData;
+
+    lxcDriverLock(driver);
+    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
+    lxcDriverUnlock(driver);
+
     conn->privateData = NULL;
     return 0;
 }
@@ -293,6 +303,8 @@ static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
     virDomainDefPtr def = NULL;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
+    virDomainEventPtr event = NULL;
+    int newVM = 1;
 
     lxcDriverLock(driver);
     if (!(def = virDomainDefParseString(conn, driver->caps, xml,
@@ -318,6 +330,12 @@ static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
         goto cleanup;
     }
 
+    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;
@@ -326,6 +344,8 @@ cleanup:
     virDomainDefFree(def);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
     return dom;
 }
@@ -334,6 +354,7 @@ static int lxcDomainUndefine(virDomainPtr dom)
 {
     lxc_driver_t *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     int ret = -1;
 
     lxcDriverLock(driver);
@@ -362,6 +383,10 @@ static int lxcDomainUndefine(virDomainPtr dom)
                               vm) < 0)
         goto cleanup;
 
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_UNDEFINED,
+                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+
     virDomainRemoveInactive(&driver->domains, vm);
     vm = NULL;
     ret = 0;
@@ -369,6 +394,8 @@ static int lxcDomainUndefine(virDomainPtr dom)
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
     return ret;
 }
@@ -532,6 +559,13 @@ static int lxcVMCleanup(virConnectPtr conn,
         virCgroupFree(&cgroup);
     }
 
+    if (vm->newDef) {
+        virDomainDefFree(vm->def);
+        vm->def = vm->newDef;
+        vm->def->id = -1;
+        vm->newDef = NULL;
+    }
+
     return rc;
 }
 
@@ -709,6 +743,7 @@ static void lxcMonitorEvent(int watch,
 {
     lxc_driver_t *driver = data;
     virDomainObjPtr vm = NULL;
+    virDomainEventPtr event = NULL;
     unsigned int i;
 
     lxcDriverLock(driver);
@@ -731,12 +766,19 @@ static void lxcMonitorEvent(int watch,
         goto cleanup;
     }
 
-    if (lxcVmTerminate(NULL, driver, vm, SIGINT) < 0)
+    if (lxcVmTerminate(NULL, driver, vm, SIGINT) < 0) {
         virEventRemoveHandle(watch);
+    } else {
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+    }
 
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
 }
 
@@ -977,6 +1019,7 @@ static int lxcDomainStart(virDomainPtr dom)
 {
     lxc_driver_t *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     int ret = -1;
 
     lxcDriverLock(driver);
@@ -995,9 +1038,16 @@ static int lxcDomainStart(virDomainPtr dom)
 
     ret = lxcVmStart(dom->conn, driver, vm);
 
+    if (ret == 0)
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STARTED,
+                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
     return ret;
 }
@@ -1020,6 +1070,7 @@ lxcDomainCreateAndStart(virConnectPtr conn,
     virDomainObjPtr vm = NULL;
     virDomainDefPtr def;
     virDomainPtr dom = NULL;
+    virDomainEventPtr event = NULL;
 
     lxcDriverLock(driver);
     if (!(def = virDomainDefParseString(conn, driver->caps, xml,
@@ -1043,6 +1094,10 @@ lxcDomainCreateAndStart(virConnectPtr conn,
         goto cleanup;
     }
 
+    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;
@@ -1051,6 +1106,8 @@ cleanup:
     virDomainDefFree(def);
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
     return dom;
 }
@@ -1067,6 +1124,7 @@ static int lxcDomainShutdown(virDomainPtr dom)
 {
     lxc_driver_t *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     int ret = -1;
 
     lxcDriverLock(driver);
@@ -1078,6 +1136,9 @@ static int lxcDomainShutdown(virDomainPtr dom)
     }
 
     ret = lxcVmTerminate(dom->conn, driver, vm, 0);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains, vm);
         vm = NULL;
@@ -1086,10 +1147,103 @@ static int lxcDomainShutdown(virDomainPtr dom)
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
+    lxcDriverUnlock(driver);
+    return ret;
+}
+
+
+static int
+lxcDomainEventRegister (virConnectPtr conn,
+                        virConnectDomainEventCallback callback,
+                        void *opaque,
+                        virFreeCallback freecb)
+{
+    lxc_driver_t *driver = conn->privateData;
+    int ret;
+
+    lxcDriverLock(driver);
+    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
+                                        callback, opaque, freecb);
     lxcDriverUnlock(driver);
+
     return ret;
 }
 
+static int
+lxcDomainEventDeregister (virConnectPtr conn,
+                          virConnectDomainEventCallback callback)
+{
+    lxc_driver_t *driver = conn->privateData;
+    int ret;
+
+    lxcDriverLock(driver);
+    if (driver->domainEventDispatching)
+        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
+                                                   callback);
+    else
+        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
+                                               callback);
+    lxcDriverUnlock(driver);
+
+    return ret;
+}
+
+static void lxcDomainEventDispatchFunc(virConnectPtr conn,
+                                       virDomainEventPtr event,
+                                       virConnectDomainEventCallback cb,
+                                       void *cbopaque,
+                                       void *opaque)
+{
+    lxc_driver_t *driver = opaque;
+
+    /* Drop the lock whle dispatching, for sake of re-entrancy */
+    lxcDriverUnlock(driver);
+    virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
+    lxcDriverLock(driver);
+}
+
+
+static void lxcDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
+{
+    lxc_driver_t *driver = opaque;
+    virDomainEventQueue tempQueue;
+
+    lxcDriverLock(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,
+                                lxcDomainEventDispatchFunc,
+                                driver);
+
+    /* Purge any deleted callbacks */
+    virDomainEventCallbackListPurgeMarked(driver->domainEventCallbacks);
+
+    driver->domainEventDispatching = 0;
+    lxcDriverUnlock(driver);
+}
+
+
+/* driver must be locked before calling */
+static void lxcDomainEventQueue(lxc_driver_t *driver,
+                                 virDomainEventPtr event)
+{
+    if (virDomainEventQueuePush(driver->domainEventQueue,
+                                event) < 0)
+        virDomainEventFree(event);
+    if (lxc_driver->domainEventQueue->count == 1)
+        virEventUpdateTimeout(driver->domainEventTimer, 0);
+}
 
 /**
  * lxcDomainDestroy:
@@ -1103,6 +1257,7 @@ static int lxcDomainDestroy(virDomainPtr dom)
 {
     lxc_driver_t *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainEventPtr event = NULL;
     int ret = -1;
 
     lxcDriverLock(driver);
@@ -1114,6 +1269,9 @@ static int lxcDomainDestroy(virDomainPtr dom)
     }
 
     ret = lxcVmTerminate(dom->conn, driver, vm, SIGKILL);
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
     if (!vm->persistent) {
         virDomainRemoveInactive(&driver->domains, vm);
         vm = NULL;
@@ -1122,6 +1280,8 @@ static int lxcDomainDestroy(virDomainPtr dom)
 cleanup:
     if (vm)
         virDomainObjUnlock(vm);
+    if (event)
+        lxcDomainEventQueue(driver, event);
     lxcDriverUnlock(driver);
     return ret;
 }
@@ -1172,6 +1332,15 @@ static int lxcStartup(int privileged)
     if(lxcContainerAvailable(0) < 0)
         goto cleanup;
 
+    if(VIR_ALLOC(lxc_driver->domainEventCallbacks) < 0)
+        goto cleanup;
+    if (!(lxc_driver->domainEventQueue = virDomainEventQueueNew()))
+        goto cleanup;
+
+    if ((lxc_driver->domainEventTimer =
+         virEventAddTimeout(-1, lxcDomainEventFlush, lxc_driver, NULL)) < 0)
+        goto cleanup;
+
     lxc_driver->have_netns = lxcCheckNetNsSupport();
 
     /* Call function to load lxc driver configuration information */
@@ -1252,6 +1421,12 @@ static int lxcShutdown(void)
     lxcDriverLock(lxc_driver);
     virDomainObjListFree(&lxc_driver->domains);
 
+    virDomainEventCallbackListFree(lxc_driver->domainEventCallbacks);
+    virDomainEventQueueFree(lxc_driver->domainEventQueue);
+
+    if (lxc_driver->domainEventTimer != -1)
+        virEventRemoveTimeout(lxc_driver->domainEventTimer);
+
     virCapabilitiesFree(lxc_driver->caps);
     VIR_FREE(lxc_driver->configDir);
     VIR_FREE(lxc_driver->autostartDir);
@@ -1490,8 +1665,8 @@ static virDriver lxcDriver = {
     NULL, /* domainMemoryPeek */
     nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
     nodeGetFreeMemory,  /* getFreeMemory */
-    NULL, /* domainEventRegister */
-    NULL, /* domainEventDeregister */
+    lxcDomainEventRegister, /* domainEventRegister */
+    lxcDomainEventDeregister, /* domainEventDeregister */
     NULL, /* domainMigratePrepare2 */
     NULL, /* domainMigrateFinish2 */
     NULL, /* nodeDeviceDettach */
-- 
1.6.2.5




More information about the libvir-list mailing list