virClassPtr virConnectClass;
+virClassPtr virConnectCloseCallbackDataClass;
virClassPtr virDomainClass;
virClassPtr virDomainSnapshotClass;
virClassPtr virInterfaceClass;
virClassPtr virStoragePoolClass;
static void virConnectDispose(void *obj);
+static void virConnectCloseCallbackDataDispose(void *obj);
static void virDomainDispose(void *obj);
static void virDomainSnapshotDispose(void *obj);
static void virInterfaceDispose(void *obj);
static int
virDataTypesOnceInit(void)
{
-#define DECLARE_CLASS(basename) \
- if (!(basename ## Class = virClassNew(virClassForObject(), \
+#define DECLARE_CLASS_COMMON(basename, parent) \
+ if (!(basename ## Class = virClassNew(parent, \
#basename, \
sizeof(basename), \
basename ## Dispose))) \
return -1;
+#define DECLARE_CLASS(basename) \
+ DECLARE_CLASS_COMMON(basename, virClassForObject())
+#define DECLARE_CLASS_LOCKABLE(basename) \
+ DECLARE_CLASS_COMMON(basename, virClassForObjectLockable())
DECLARE_CLASS(virConnect);
+ DECLARE_CLASS_LOCKABLE(virConnectCloseCallbackData);
DECLARE_CLASS(virDomain);
DECLARE_CLASS(virDomainSnapshot);
DECLARE_CLASS(virInterface);
DECLARE_CLASS(virStorageVol);
DECLARE_CLASS(virStoragePool);
+#undef DECLARE_CLASS_COMMON
+#undef DECLARE_CLASS_LOCKABLE
#undef DECLARE_CLASS
return 0;
if (!(ret = virObjectNew(virConnectClass)))
return NULL;
- if (virMutexInit(&ret->lock) < 0) {
- VIR_FREE(ret);
- return NULL;
- }
+ if (!(ret->closeCallback = virObjectNew(virConnectCloseCallbackDataClass)))
+ goto error;
+
+ if (virMutexInit(&ret->lock) < 0)
+ goto error;
return ret;
+
+error:
+ virObjectUnref(ret);
+ return NULL;
}
/**
virMutexLock(&conn->lock);
- if (conn->closeFreeCallback)
- conn->closeFreeCallback(conn->closeOpaque);
-
virResetError(&conn->err);
virURIFree(conn->uri);
+ virObjectLock(conn->closeCallback);
+ conn->closeCallback->callback = NULL;
+ virObjectUnlock(conn->closeCallback);
+
+ virObjectUnref(conn->closeCallback);
+
virMutexUnlock(&conn->lock);
virMutexDestroy(&conn->lock);
}
+/**
+ * virConnectCloseCallbackDataDispose:
+ * @obj: the close callback data to release
+ *
+ * Release resources bound to the connection close callback.
+ */
+static void
+virConnectCloseCallbackDataDispose(void *obj)
+{
+ virConnectCloseCallbackDataPtr cb = obj;
+
+ virObjectLock(cb);
+
+ if (cb->freeCallback)
+ cb->freeCallback(cb->opaque);
+
+ virObjectUnlock(cb);
+}
+
+
/**
* virGetDomain:
* @conn: the hypervisor connection
# define VIR_IS_DOMAIN_SNAPSHOT(obj) \
(VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain))
+
+typedef struct _virConnectCloseCallbackData virConnectCloseCallbackData;
+typedef virConnectCloseCallbackData *virConnectCloseCallbackDataPtr;
+
+/**
+ * Internal structure holding data related to connection close callbacks.
+ */
+struct _virConnectCloseCallbackData {
+ virObjectLockable parent;
+
+ virConnectPtr conn;
+ virConnectCloseFunc callback;
+ void *opaque;
+ virFreeCallback freeCallback;
+};
+
/**
* _virConnect:
*
void *userData; /* the user data */
/* Per-connection close callback */
- virConnectCloseFunc closeCallback;
- void *closeOpaque;
- virFreeCallback closeFreeCallback;
- bool closeDispatch;
- unsigned closeUnregisterCount;
+ virConnectCloseCallbackDataPtr closeCallback;
};
/**
virObjectRef(conn);
virMutexLock(&conn->lock);
+ virObjectLock(conn->closeCallback);
virCheckNonNullArgGoto(cb, error);
- if (conn->closeCallback) {
+ if (conn->closeCallback->callback) {
virLibConnError(VIR_ERR_OPERATION_INVALID, "%s",
_("A close callback is already registered"));
goto error;
}
- conn->closeCallback = cb;
- conn->closeOpaque = opaque;
- conn->closeFreeCallback = freecb;
+ conn->closeCallback->callback = cb;
+ conn->closeCallback->opaque = opaque;
+ conn->closeCallback->freeCallback = freecb;
+ virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
return 0;
error:
+ virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
virObjectUnref(conn);
virDispatchError(NULL);
}
virMutexLock(&conn->lock);
+ virObjectLock(conn->closeCallback);
virCheckNonNullArgGoto(cb, error);
- if (conn->closeCallback != cb) {
+ if (conn->closeCallback->callback != cb) {
virLibConnError(VIR_ERR_OPERATION_INVALID, "%s",
_("A different callback was requested"));
goto error;
}
- conn->closeCallback = NULL;
- conn->closeUnregisterCount++;
- if (!conn->closeDispatch && conn->closeFreeCallback)
- conn->closeFreeCallback(conn->closeOpaque);
- conn->closeFreeCallback = NULL;
- conn->closeOpaque = NULL;
-
- virMutexUnlock(&conn->lock);
+ conn->closeCallback->callback = NULL;
+ if (conn->closeCallback->freeCallback)
+ conn->closeCallback->freeCallback(conn->closeCallback->opaque);
+ conn->closeCallback->freeCallback = NULL;
virObjectUnref(conn);
+ virObjectUnlock(conn->closeCallback);
+ virMutexUnlock(&conn->lock);
return 0;
error:
+ virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
virDispatchError(NULL);
return -1;
};
-static void remoteClientCloseFunc(virNetClientPtr client ATTRIBUTE_UNUSED,
- int reason,
- void *opaque)
+static void
+remoteClientCloseFunc(virNetClientPtr client ATTRIBUTE_UNUSED,
+ int reason,
+ void *opaque)
{
- virConnectPtr conn = opaque;
+ virConnectCloseCallbackDataPtr cbdata = opaque;
- virMutexLock(&conn->lock);
- if (conn->closeCallback) {
- virConnectCloseFunc closeCallback = conn->closeCallback;
- void *closeOpaque = conn->closeOpaque;
- virFreeCallback closeFreeCallback = conn->closeFreeCallback;
- unsigned closeUnregisterCount = conn->closeUnregisterCount;
+ virObjectLock(cbdata);
- VIR_DEBUG("Triggering connection close callback %p reason=%d",
- conn->closeCallback, reason);
- conn->closeDispatch = true;
- virMutexUnlock(&conn->lock);
- closeCallback(conn, reason, closeOpaque);
- virMutexLock(&conn->lock);
- conn->closeDispatch = false;
- if (conn->closeUnregisterCount != closeUnregisterCount &&
- closeFreeCallback)
- closeFreeCallback(closeOpaque);
+ if (cbdata->callback) {
+ VIR_DEBUG("Triggering connection close callback %p reason=%d, opaque=%p",
+ cbdata->callback, reason, cbdata->opaque);
+ cbdata->callback(cbdata->conn, reason, cbdata->opaque);
+
+ if (cbdata->freeCallback)
+ cbdata->freeCallback(cbdata->opaque);
+ cbdata->callback = NULL;
+ cbdata->freeCallback = NULL;
}
- virMutexUnlock(&conn->lock);
+ virObjectUnlock(cbdata);
+
+ /* free the connection reference that comes along with the callback
+ * registration */
+ virObjectUnref(cbdata->conn);
}
/* helper macro to ease extraction of arguments from the URI */
goto failed;
}
+ virObjectRef(conn->closeCallback);
+
virNetClientSetCloseCallback(priv->client,
remoteClientCloseFunc,
- conn, NULL);
+ conn->closeCallback, virObjectFreeCallback);
if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM,
REMOTE_PROTOCOL_VERSION,
virObjectUnref(priv->tls);
priv->tls = NULL;
#endif
+
virNetClientSetCloseCallback(priv->client,
NULL,
- NULL,
- NULL);
+ conn->closeCallback, virObjectFreeCallback);
+
virNetClientClose(priv->client);
virObjectUnref(priv->client);
priv->client = NULL;