[libvirt] [PATCH 1/9] qemu: Move close callbacks handling into util/virclosecallbacks.c

Michal Privoznik mprivozn at redhat.com
Wed Jul 17 13:04:18 UTC 2013


---
 po/POTFILES.in               |   1 +
 src/Makefile.am              |   4 +-
 src/libvirt_private.syms     |   7 +
 src/qemu/qemu_conf.c         | 295 +-------------------------------------
 src/qemu/qemu_conf.h         |  25 +---
 src/qemu/qemu_driver.c       |   4 +-
 src/qemu/qemu_migration.c    |  18 +--
 src/qemu/qemu_migration.h    |   2 +-
 src/qemu/qemu_process.c      |  14 +-
 src/util/virclosecallbacks.c | 332 +++++++++++++++++++++++++++++++++++++++++++
 src/util/virclosecallbacks.h |  53 +++++++
 11 files changed, 418 insertions(+), 337 deletions(-)
 create mode 100644 src/util/virclosecallbacks.c
 create mode 100644 src/util/virclosecallbacks.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0b65765..2e4ebc8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -146,6 +146,7 @@ src/util/viraudit.c
 src/util/virauth.c
 src/util/virauthconfig.c
 src/util/vircgroup.c
+src/util/virclosecallbacks.c
 src/util/vircommand.c
 src/util/virconf.c
 src/util/virdbus.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d9e703f..8fa8680 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -83,6 +83,7 @@ UTIL_SOURCES =							\
 		util/virbitmap.c util/virbitmap.h		\
 		util/virbuffer.c util/virbuffer.h		\
 		util/vircgroup.c util/vircgroup.h util/vircgrouppriv.h	\
+		util/virclosecallbacks.c util/virclosecallbacks.h		\
 		util/vircommand.c util/vircommand.h		\
 		util/virconf.c util/virconf.h			\
 		util/virdbus.c util/virdbus.h			\
@@ -882,7 +883,8 @@ libvirt_util_la_SOURCES =					\
 		$(UTIL_SOURCES)
 libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
 		$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \
-		$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS)
+		$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS)	\
+		-I$(top_srcdir)/src/conf
 libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
 		$(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
 		$(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fc4e750..53b1153 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1204,6 +1204,13 @@ virCgroupSetMemorySoftLimit;
 virCgroupSetMemSwapHardLimit;
 
 
+# util/virclosecallbacks.h
+virCloseCallbacksGet;
+virCloseCallbacksNew;
+virCloseCallbacksRun;
+virCloseCallbacksSet;
+virCloseCallbacksUnset;
+
 # util/vircommand.h
 virCommandAbort;
 virCommandAddArg;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index c91551f..64214b9 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -56,25 +56,8 @@
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
-typedef struct _qemuDriverCloseDef qemuDriverCloseDef;
-typedef qemuDriverCloseDef *qemuDriverCloseDefPtr;
-struct _qemuDriverCloseDef {
-    virConnectPtr conn;
-    virQEMUCloseCallback cb;
-};
-
-struct _virQEMUCloseCallbacks {
-    virObjectLockable parent;
-
-    /* UUID string to qemuDriverCloseDef mapping */
-    virHashTablePtr list;
-};
-
-
 static virClassPtr virQEMUDriverConfigClass;
-static virClassPtr virQEMUCloseCallbacksClass;
 static void virQEMUDriverConfigDispose(void *obj);
-static void virQEMUCloseCallbacksDispose(void *obj);
 
 static int virQEMUConfigOnceInit(void)
 {
@@ -83,12 +66,7 @@ static int virQEMUConfigOnceInit(void)
                                            sizeof(virQEMUDriverConfig),
                                            virQEMUDriverConfigDispose);
 
-    virQEMUCloseCallbacksClass = virClassNew(virClassForObjectLockable(),
-                                             "virQEMUCloseCallbacks",
-                                             sizeof(virQEMUCloseCallbacks),
-                                             virQEMUCloseCallbacksDispose);
-
-    if (!virQEMUDriverConfigClass || !virQEMUCloseCallbacksClass)
+    if (!virQEMUDriverConfigClass)
         return -1;
     else
         return 0;
@@ -662,277 +640,6 @@ virCapsPtr virQEMUDriverGetCapabilities(virQEMUDriverPtr driver,
     return ret;
 }
 
-
-static void
-virQEMUCloseCallbacksFreeData(void *payload,
-                              const void *name ATTRIBUTE_UNUSED)
-{
-    VIR_FREE(payload);
-}
-
-virQEMUCloseCallbacksPtr
-virQEMUCloseCallbacksNew(void)
-{
-    virQEMUCloseCallbacksPtr closeCallbacks;
-
-    if (virQEMUConfigInitialize() < 0)
-        return NULL;
-
-    if (!(closeCallbacks = virObjectLockableNew(virQEMUCloseCallbacksClass)))
-        return NULL;
-
-    closeCallbacks->list = virHashCreate(5, virQEMUCloseCallbacksFreeData);
-    if (!closeCallbacks->list) {
-        virObjectUnref(closeCallbacks);
-        return NULL;
-    }
-
-    return closeCallbacks;
-}
-
-static void
-virQEMUCloseCallbacksDispose(void *obj)
-{
-    virQEMUCloseCallbacksPtr closeCallbacks = obj;
-
-    virHashFree(closeCallbacks->list);
-}
-
-int
-virQEMUCloseCallbacksSet(virQEMUCloseCallbacksPtr closeCallbacks,
-                         virDomainObjPtr vm,
-                         virConnectPtr conn,
-                         virQEMUCloseCallback cb)
-{
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-    qemuDriverCloseDefPtr closeDef;
-    int ret = -1;
-
-    virUUIDFormat(vm->def->uuid, uuidstr);
-    VIR_DEBUG("vm=%s, uuid=%s, conn=%p, cb=%p",
-              vm->def->name, uuidstr, conn, cb);
-
-    virObjectLock(closeCallbacks);
-
-    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
-    if (closeDef) {
-        if (closeDef->conn != conn) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Close callback for domain %s already registered"
-                             " with another connection %p"),
-                           vm->def->name, closeDef->conn);
-            goto cleanup;
-        }
-        if (closeDef->cb && closeDef->cb != cb) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Another close callback is already defined for"
-                             " domain %s"), vm->def->name);
-            goto cleanup;
-        }
-
-        closeDef->cb = cb;
-    } else {
-        if (VIR_ALLOC(closeDef) < 0)
-            goto cleanup;
-
-        closeDef->conn = conn;
-        closeDef->cb = cb;
-        if (virHashAddEntry(closeCallbacks->list, uuidstr, closeDef) < 0) {
-            VIR_FREE(closeDef);
-            goto cleanup;
-        }
-    }
-
-    ret = 0;
-cleanup:
-    virObjectUnlock(closeCallbacks);
-    return ret;
-}
-
-int
-virQEMUCloseCallbacksUnset(virQEMUCloseCallbacksPtr closeCallbacks,
-                           virDomainObjPtr vm,
-                           virQEMUCloseCallback cb)
-{
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-    qemuDriverCloseDefPtr closeDef;
-    int ret = -1;
-
-    virUUIDFormat(vm->def->uuid, uuidstr);
-    VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
-              vm->def->name, uuidstr, cb);
-
-    virObjectLock(closeCallbacks);
-
-    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
-    if (!closeDef)
-        goto cleanup;
-
-    if (closeDef->cb && closeDef->cb != cb) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Trying to remove mismatching close callback for"
-                         " domain %s"), vm->def->name);
-        goto cleanup;
-    }
-
-    ret = virHashRemoveEntry(closeCallbacks->list, uuidstr);
-cleanup:
-    virObjectUnlock(closeCallbacks);
-    return ret;
-}
-
-virQEMUCloseCallback
-virQEMUCloseCallbacksGet(virQEMUCloseCallbacksPtr closeCallbacks,
-                         virDomainObjPtr vm,
-                         virConnectPtr conn)
-{
-    char uuidstr[VIR_UUID_STRING_BUFLEN];
-    qemuDriverCloseDefPtr closeDef;
-    virQEMUCloseCallback cb = NULL;
-
-    virUUIDFormat(vm->def->uuid, uuidstr);
-    VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
-              vm->def->name, uuidstr, conn);
-
-    virObjectLock(closeCallbacks);
-
-    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
-    if (closeDef && (!conn || closeDef->conn == conn))
-        cb = closeDef->cb;
-
-    virObjectUnlock(closeCallbacks);
-
-    VIR_DEBUG("cb=%p", cb);
-    return cb;
-}
-
-
-typedef struct _virQEMUCloseCallbacksListEntry virQEMUCloseCallbacksListEntry;
-typedef virQEMUCloseCallbacksListEntry *virQEMUCloseCallbacksListEntryPtr;
-struct _virQEMUCloseCallbacksListEntry {
-    unsigned char uuid[VIR_UUID_BUFLEN];
-    virQEMUCloseCallback callback;
-};
-
-
-typedef struct _virQEMUCloseCallbacksList virQEMUCloseCallbacksList;
-typedef virQEMUCloseCallbacksList *virQEMUCloseCallbacksListPtr;
-struct _virQEMUCloseCallbacksList {
-    size_t nentries;
-    virQEMUCloseCallbacksListEntryPtr entries;
-};
-
-
-struct virQEMUCloseCallbacksData {
-    virConnectPtr conn;
-    virQEMUCloseCallbacksListPtr list;
-    bool oom;
-};
-
-
-static void
-virQEMUCloseCallbacksGetOne(void *payload,
-                            const void *key,
-                            void *opaque)
-{
-    struct virQEMUCloseCallbacksData *data = opaque;
-    qemuDriverCloseDefPtr closeDef = payload;
-    const char *uuidstr = key;
-    unsigned char uuid[VIR_UUID_BUFLEN];
-
-    if (virUUIDParse(uuidstr, uuid) < 0)
-        return;
-
-    VIR_DEBUG("conn=%p, thisconn=%p, uuid=%s, cb=%p",
-              closeDef->conn, data->conn, uuidstr, closeDef->cb);
-
-    if (data->conn != closeDef->conn || !closeDef->cb)
-        return;
-
-    if (VIR_EXPAND_N(data->list->entries,
-                     data->list->nentries, 1) < 0) {
-        data->oom = true;
-        return;
-    }
-
-    memcpy(data->list->entries[data->list->nentries - 1].uuid,
-           uuid, VIR_UUID_BUFLEN);
-    data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
-}
-
-
-static virQEMUCloseCallbacksListPtr
-virQEMUCloseCallbacksGetForConn(virQEMUCloseCallbacksPtr closeCallbacks,
-                                virConnectPtr conn)
-{
-    virQEMUCloseCallbacksListPtr list = NULL;
-    struct virQEMUCloseCallbacksData data;
-
-    if (VIR_ALLOC(list) < 0)
-        return NULL;
-
-    data.conn = conn;
-    data.list = list;
-    data.oom = false;
-
-    virHashForEach(closeCallbacks->list, virQEMUCloseCallbacksGetOne, &data);
-
-    if (data.oom) {
-        VIR_FREE(list->entries);
-        VIR_FREE(list);
-        virReportOOMError();
-        return NULL;
-    }
-
-    return list;
-}
-
-
-void
-virQEMUCloseCallbacksRun(virQEMUCloseCallbacksPtr closeCallbacks,
-                         virConnectPtr conn,
-                         virQEMUDriverPtr driver)
-{
-    virQEMUCloseCallbacksListPtr list;
-    size_t i;
-
-    VIR_DEBUG("conn=%p", conn);
-
-    /* We must not hold the lock while running the callbacks,
-     * so first we obtain the list of callbacks, then remove
-     * them all from the hash. At that point we can release
-     * the lock and run the callbacks safely. */
-
-    virObjectLock(closeCallbacks);
-    list = virQEMUCloseCallbacksGetForConn(closeCallbacks, conn);
-    if (!list)
-        return;
-
-    for (i = 0; i < list->nentries; i++) {
-        virHashRemoveEntry(closeCallbacks->list,
-                           list->entries[i].uuid);
-    }
-    virObjectUnlock(closeCallbacks);
-
-    for (i = 0; i < list->nentries; i++) {
-        virDomainObjPtr vm;
-
-        if (!(vm = virDomainObjListFindByUUID(driver->domains,
-                                              list->entries[i].uuid))) {
-            char uuidstr[VIR_UUID_STRING_BUFLEN];
-            virUUIDFormat(list->entries[i].uuid, uuidstr);
-            VIR_DEBUG("No domain object with UUID %s", uuidstr);
-            continue;
-        }
-
-        vm = list->entries[i].callback(driver, vm, conn);
-        if (vm)
-            virObjectUnlock(vm);
-    }
-    VIR_FREE(list->entries);
-    VIR_FREE(list);
-}
-
 struct _qemuSharedDeviceEntry {
     size_t ref;
     char **domains; /* array of domain names */
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 19893c8..8229cfc 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -42,6 +42,7 @@
 # include "virthreadpool.h"
 # include "locking/lock_manager.h"
 # include "qemu_capabilities.h"
+# include "virclosecallbacks.h"
 
 # ifdef CPU_SETSIZE /* Linux */
 #  define QEMUD_CPUMASK_LEN CPU_SETSIZE
@@ -51,9 +52,6 @@
 #  error "Port me"
 # endif
 
-typedef struct _virQEMUCloseCallbacks virQEMUCloseCallbacks;
-typedef virQEMUCloseCallbacks *virQEMUCloseCallbacksPtr;
-
 typedef struct _virQEMUDriver virQEMUDriver;
 typedef virQEMUDriver *virQEMUDriverPtr;
 
@@ -229,7 +227,7 @@ struct _virQEMUDriver {
     virLockManagerPluginPtr lockManager;
 
     /* Immutable pointer, self-clocking APIs */
-    virQEMUCloseCallbacksPtr closeCallbacks;
+    virCloseCallbacksPtr closeCallbacks;
 };
 
 typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
@@ -266,25 +264,6 @@ struct qemuDomainDiskInfo {
     int io_status;
 };
 
-typedef virDomainObjPtr (*virQEMUCloseCallback)(virQEMUDriverPtr driver,
-                                                virDomainObjPtr vm,
-                                                virConnectPtr conn);
-virQEMUCloseCallbacksPtr virQEMUCloseCallbacksNew(void);
-int virQEMUCloseCallbacksSet(virQEMUCloseCallbacksPtr closeCallbacks,
-                             virDomainObjPtr vm,
-                             virConnectPtr conn,
-                             virQEMUCloseCallback cb);
-int virQEMUCloseCallbacksUnset(virQEMUCloseCallbacksPtr closeCallbacks,
-                               virDomainObjPtr vm,
-                               virQEMUCloseCallback cb);
-virQEMUCloseCallback
-virQEMUCloseCallbacksGet(virQEMUCloseCallbacksPtr closeCallbacks,
-                         virDomainObjPtr vm,
-                         virConnectPtr conn);
-void virQEMUCloseCallbacksRun(virQEMUCloseCallbacksPtr closeCallbacks,
-                              virConnectPtr conn,
-                              virQEMUDriverPtr driver);
-
 typedef struct _qemuSharedDeviceEntry qemuSharedDeviceEntry;
 typedef qemuSharedDeviceEntry *qemuSharedDeviceEntryPtr;
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b7b066d..dab0513 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -776,7 +776,7 @@ qemuStateInitialize(bool privileged,
         cfg->hugepagePath = mempath;
     }
 
-    if (!(qemu_driver->closeCallbacks = virQEMUCloseCallbacksNew()))
+    if (!(qemu_driver->closeCallbacks = virCloseCallbacksNew()))
         goto error;
 
     /* Get all the running persistent or transient configs first */
@@ -1076,7 +1076,7 @@ static int qemuConnectClose(virConnectPtr conn)
     virQEMUDriverPtr driver = conn->privateData;
 
     /* Get rid of callbacks registered for this conn */
-    virQEMUCloseCallbacksRun(driver->closeCallbacks, conn, driver);
+    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
 
     conn->privateData = NULL;
 
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 62e0cbc..19343a6 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1897,7 +1897,7 @@ cleanup:
  * qemuDomainMigratePerform3 and qemuDomainMigrateConfirm3.
  */
 virDomainObjPtr
-qemuMigrationCleanup(virQEMUDriverPtr driver,
+qemuMigrationCleanup(void *driver,
                      virDomainObjPtr vm,
                      virConnectPtr conn)
 {
@@ -2100,8 +2100,8 @@ qemuMigrationBegin(virConnectPtr conn,
          * This prevents any other APIs being invoked while migration is taking
          * place.
          */
-        if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
-                                     qemuMigrationCleanup) < 0)
+        if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
+                                 qemuMigrationCleanup) < 0)
             goto endjob;
         if (qemuMigrationJobContinue(vm) == 0) {
             vm = NULL;
@@ -2750,8 +2750,8 @@ qemuMigrationConfirm(virConnectPtr conn,
         phase = QEMU_MIGRATION_PHASE_CONFIRM3;
 
     qemuMigrationJobStartPhase(driver, vm, phase);
-    virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
-                               qemuMigrationCleanup);
+    virCloseCallbacksUnset(driver->closeCallbacks, vm,
+                           qemuMigrationCleanup);
 
     ret = qemuMigrationConfirmPhase(driver, conn, vm,
                                     cookiein, cookieinlen,
@@ -4123,8 +4123,8 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
     }
 
     qemuMigrationJobStartPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
-    virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
-                               qemuMigrationCleanup);
+    virCloseCallbacksUnset(driver->closeCallbacks, vm,
+                           qemuMigrationCleanup);
 
     resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
     ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
@@ -4155,8 +4155,8 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
 
     qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);
 
-    if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
-                                 qemuMigrationCleanup) < 0)
+    if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
+                             qemuMigrationCleanup) < 0)
         goto endjob;
 
 endjob:
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 43b26de..bf962b1 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -90,7 +90,7 @@ bool qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr obj)
 int qemuMigrationSetOffline(virQEMUDriverPtr driver,
                             virDomainObjPtr vm);
 
-virDomainObjPtr qemuMigrationCleanup(virQEMUDriverPtr driver,
+virDomainObjPtr qemuMigrationCleanup(void *driver,
                                      virDomainObjPtr vm,
                                      virConnectPtr conn);
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 3d5e8f6..9b4a448 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4468,7 +4468,7 @@ cleanup:
 
 
 static virDomainObjPtr
-qemuProcessAutoDestroy(virQEMUDriverPtr driver,
+qemuProcessAutoDestroy(void *driver,
                        virDomainObjPtr dom,
                        virConnectPtr conn)
 {
@@ -4515,23 +4515,23 @@ int qemuProcessAutoDestroyAdd(virQEMUDriverPtr driver,
                               virConnectPtr conn)
 {
     VIR_DEBUG("vm=%s, conn=%p", vm->def->name, conn);
-    return virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, conn,
-                                    qemuProcessAutoDestroy);
+    return virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
+                                qemuProcessAutoDestroy);
 }
 
 int qemuProcessAutoDestroyRemove(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm)
 {
     VIR_DEBUG("vm=%s", vm->def->name);
-    return virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
-                                      qemuProcessAutoDestroy);
+    return virCloseCallbacksUnset(driver->closeCallbacks, vm,
+                                  qemuProcessAutoDestroy);
 }
 
 bool qemuProcessAutoDestroyActive(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm)
 {
-    virQEMUCloseCallback cb;
+    virCloseCallback cb;
     VIR_DEBUG("vm=%s", vm->def->name);
-    cb = virQEMUCloseCallbacksGet(driver->closeCallbacks, vm, NULL);
+    cb = virCloseCallbacksGet(driver->closeCallbacks, vm, NULL);
     return cb == qemuProcessAutoDestroy;
 }
diff --git a/src/util/virclosecallbacks.c b/src/util/virclosecallbacks.c
new file mode 100644
index 0000000..a926456
--- /dev/null
+++ b/src/util/virclosecallbacks.c
@@ -0,0 +1,332 @@
+/*
+ * virclosecallbacks.c: Connection close callbacks routines
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Daniel P. Berrange <berrange at redhat.com>
+ *      Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virclosecallbacks.h"
+#include "virlog.h"
+#include "virobject.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+typedef struct _virDriverCloseDef virDriverCloseDef;
+typedef virDriverCloseDef *virDriverCloseDefPtr;
+struct _virDriverCloseDef {
+    virConnectPtr conn;
+    virCloseCallback cb;
+};
+
+struct _virCloseCallbacks {
+    virObjectLockable parent;
+
+    /* UUID string to qemuDriverCloseDef mapping */
+    virHashTablePtr list;
+};
+
+
+static virClassPtr virCloseCallbacksClass;
+static void virCloseCallbacksDispose(void *obj);
+
+static int virCloseCallbacksOnceInit(void)
+{
+    virCloseCallbacksClass = virClassNew(virClassForObjectLockable(),
+                                         "virCloseCallbacks",
+                                         sizeof(virCloseCallbacks),
+                                         virCloseCallbacksDispose);
+
+    if (!virCloseCallbacksClass)
+        return -1;
+    else
+        return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virCloseCallbacks)
+
+
+static void
+virCloseCallbacksFreeData(void *payload,
+                          const void *name ATTRIBUTE_UNUSED)
+{
+    VIR_FREE(payload);
+}
+
+virCloseCallbacksPtr
+virCloseCallbacksNew(void)
+{
+    virCloseCallbacksPtr closeCallbacks;
+
+    if (virCloseCallbacksInitialize() < 0)
+        return NULL;
+
+    if (!(closeCallbacks = virObjectLockableNew(virCloseCallbacksClass)))
+        return NULL;
+
+    closeCallbacks->list = virHashCreate(5, virCloseCallbacksFreeData);
+    if (!closeCallbacks->list) {
+        virObjectUnref(closeCallbacks);
+        return NULL;
+    }
+
+    return closeCallbacks;
+}
+
+static void
+virCloseCallbacksDispose(void *obj)
+{
+    virCloseCallbacksPtr closeCallbacks = obj;
+
+    virHashFree(closeCallbacks->list);
+}
+
+int
+virCloseCallbacksSet(virCloseCallbacksPtr closeCallbacks,
+                     virDomainObjPtr vm,
+                     virConnectPtr conn,
+                     virCloseCallback cb)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virDriverCloseDefPtr closeDef;
+    int ret = -1;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, conn=%p, cb=%p",
+              vm->def->name, uuidstr, conn, cb);
+
+    virObjectLock(closeCallbacks);
+
+    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+    if (closeDef) {
+        if (closeDef->conn != conn) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Close callback for domain %s already registered"
+                             " with another connection %p"),
+                           vm->def->name, closeDef->conn);
+            goto cleanup;
+        }
+        if (closeDef->cb && closeDef->cb != cb) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Another close callback is already defined for"
+                             " domain %s"), vm->def->name);
+            goto cleanup;
+        }
+
+        closeDef->cb = cb;
+    } else {
+        if (VIR_ALLOC(closeDef) < 0)
+            goto cleanup;
+
+        closeDef->conn = conn;
+        closeDef->cb = cb;
+        if (virHashAddEntry(closeCallbacks->list, uuidstr, closeDef) < 0) {
+            VIR_FREE(closeDef);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+cleanup:
+    virObjectUnlock(closeCallbacks);
+    return ret;
+}
+
+int
+virCloseCallbacksUnset(virCloseCallbacksPtr closeCallbacks,
+                       virDomainObjPtr vm,
+                       virCloseCallback cb)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virDriverCloseDefPtr closeDef;
+    int ret = -1;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
+              vm->def->name, uuidstr, cb);
+
+    virObjectLock(closeCallbacks);
+
+    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+    if (!closeDef)
+        goto cleanup;
+
+    if (closeDef->cb && closeDef->cb != cb) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Trying to remove mismatching close callback for"
+                         " domain %s"), vm->def->name);
+        goto cleanup;
+    }
+
+    ret = virHashRemoveEntry(closeCallbacks->list, uuidstr);
+cleanup:
+    virObjectUnlock(closeCallbacks);
+    return ret;
+}
+
+virCloseCallback
+virCloseCallbacksGet(virCloseCallbacksPtr closeCallbacks,
+                     virDomainObjPtr vm,
+                     virConnectPtr conn)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virDriverCloseDefPtr closeDef;
+    virCloseCallback cb = NULL;
+
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
+              vm->def->name, uuidstr, conn);
+
+    virObjectLock(closeCallbacks);
+
+    closeDef = virHashLookup(closeCallbacks->list, uuidstr);
+    if (closeDef && (!conn || closeDef->conn == conn))
+        cb = closeDef->cb;
+
+    virObjectUnlock(closeCallbacks);
+
+    VIR_DEBUG("cb=%p", cb);
+    return cb;
+}
+
+typedef struct _virCloseCallbacksListEntry virCloseCallbacksListEntry;
+typedef virCloseCallbacksListEntry *virCloseCallbacksListEntryPtr;
+struct _virCloseCallbacksListEntry {
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    virCloseCallback callback;
+};
+
+typedef struct _virCloseCallbacksList virCloseCallbacksList;
+typedef virCloseCallbacksList *virCloseCallbacksListPtr;
+struct _virCloseCallbacksList {
+    size_t nentries;
+    virCloseCallbacksListEntryPtr entries;
+};
+
+struct virCloseCallbacksData {
+    virConnectPtr conn;
+    virCloseCallbacksListPtr list;
+    bool oom;
+};
+
+static void
+virCloseCallbacksGetOne(void *payload,
+                        const void *key,
+                        void *opaque)
+{
+    struct virCloseCallbacksData *data = opaque;
+    virDriverCloseDefPtr closeDef = payload;
+    const char *uuidstr = key;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+
+    if (virUUIDParse(uuidstr, uuid) < 0)
+        return;
+
+    VIR_DEBUG("conn=%p, thisconn=%p, uuid=%s, cb=%p",
+              closeDef->conn, data->conn, uuidstr, closeDef->cb);
+
+    if (data->conn != closeDef->conn || !closeDef->cb)
+        return;
+
+    if (VIR_EXPAND_N(data->list->entries,
+                     data->list->nentries, 1) < 0) {
+        data->oom = true;
+        return;
+    }
+
+    memcpy(data->list->entries[data->list->nentries - 1].uuid,
+           uuid, VIR_UUID_BUFLEN);
+    data->list->entries[data->list->nentries - 1].callback = closeDef->cb;
+}
+
+static virCloseCallbacksListPtr
+virCloseCallbacksGetForConn(virCloseCallbacksPtr closeCallbacks,
+                            virConnectPtr conn)
+{
+    virCloseCallbacksListPtr list = NULL;
+    struct virCloseCallbacksData data;
+
+    if (VIR_ALLOC(list) < 0)
+        return NULL;
+
+    data.conn = conn;
+    data.list = list;
+    data.oom = false;
+
+    virHashForEach(closeCallbacks->list, virCloseCallbacksGetOne, &data);
+
+    if (data.oom) {
+        VIR_FREE(list->entries);
+        VIR_FREE(list);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return list;
+}
+
+
+void
+virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
+                     virConnectPtr conn,
+                     virDomainObjListPtr domains,
+                     void *driver)
+{
+    virCloseCallbacksListPtr list;
+    size_t i;
+
+    VIR_DEBUG("conn=%p", conn);
+
+    /* We must not hold the lock while running the callbacks,
+     * so first we obtain the list of callbacks, then remove
+     * them all from the hash. At that point we can release
+     * the lock and run the callbacks safely. */
+
+    virObjectLock(closeCallbacks);
+    list = virCloseCallbacksGetForConn(closeCallbacks, conn);
+    if (!list)
+        return;
+
+    for (i = 0; i < list->nentries; i++) {
+        virHashRemoveEntry(closeCallbacks->list,
+                           list->entries[i].uuid);
+    }
+    virObjectUnlock(closeCallbacks);
+
+    for (i = 0; i < list->nentries; i++) {
+        virDomainObjPtr vm;
+
+        if (!(vm = virDomainObjListFindByUUID(domains,
+                                              list->entries[i].uuid))) {
+            char uuidstr[VIR_UUID_STRING_BUFLEN];
+            virUUIDFormat(list->entries[i].uuid, uuidstr);
+            VIR_DEBUG("No domain object with UUID %s", uuidstr);
+            continue;
+        }
+
+        vm = list->entries[i].callback(driver, vm, conn);
+        if (vm)
+            virObjectUnlock(vm);
+    }
+    VIR_FREE(list->entries);
+    VIR_FREE(list);
+}
diff --git a/src/util/virclosecallbacks.h b/src/util/virclosecallbacks.h
new file mode 100644
index 0000000..9db641f
--- /dev/null
+++ b/src/util/virclosecallbacks.h
@@ -0,0 +1,53 @@
+/*
+ * virclosecallbacks.h: Connection close callbacks routines
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Daniel P. Berrange <berrange at redhat.com>
+ *      Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#ifndef __VIR_CLOSE_CALLBACKS__
+# define __VIR_CLOSE_CALLBACKS__
+
+# include "domain_conf.h"
+
+typedef struct _virCloseCallbacks virCloseCallbacks;
+typedef virCloseCallbacks *virCloseCallbacksPtr;
+
+typedef virDomainObjPtr (*virCloseCallback)(void *driver,
+                                            virDomainObjPtr vm,
+                                            virConnectPtr conn);
+virCloseCallbacksPtr virCloseCallbacksNew(void);
+int virCloseCallbacksSet(virCloseCallbacksPtr closeCallbacks,
+                         virDomainObjPtr vm,
+                         virConnectPtr conn,
+                         virCloseCallback cb);
+int virCloseCallbacksUnset(virCloseCallbacksPtr closeCallbacks,
+                           virDomainObjPtr vm,
+                           virCloseCallback cb);
+virCloseCallback
+virCloseCallbacksGet(virCloseCallbacksPtr closeCallbacks,
+                     virDomainObjPtr vm,
+                     virConnectPtr conn);
+void
+virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
+                     virConnectPtr conn,
+                     virDomainObjListPtr domains,
+                     void *driver);
+#endif /* __VIR_CLOSE_CALLBACKS__ */
-- 
1.8.1.5




More information about the libvir-list mailing list