---
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(a)redhat.com>
+ * Michal Privoznik <mprivozn(a)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(a)redhat.com>
+ * Michal Privoznik <mprivozn(a)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