diff --git a/src/datatypes.c b/src/datatypes.c index f9f0b5666c..163db398bf 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -118,22 +118,10 @@ VIR_ONCE_GLOBAL_INIT(virDataTypes) virConnectPtr virGetConnect(void) { - virConnectPtr ret; - if (virDataTypesInitialize() < 0) return NULL; - if (!(ret = virObjectLockableNew(virConnectClass))) - return NULL; - - if (!(ret->closeCallback = virObjectLockableNew(virConnectCloseCallbackDataClass))) - goto error; - - return ret; - - error: - virObjectUnref(ret); - return NULL; + return virObjectLockableNew(virConnectClass); } /** @@ -154,14 +142,6 @@ virConnectDispose(void *obj) virResetError(&conn->err); virURIFree(conn->uri); - - if (conn->closeCallback) { - virObjectLock(conn->closeCallback); - conn->closeCallback->callback = NULL; - virObjectUnlock(conn->closeCallback); - - virObjectUnref(conn->closeCallback); - } } @@ -189,6 +169,15 @@ virConnectCloseCallbackDataDispose(void *obj) virConnectCloseCallbackDataReset(obj); } +virConnectCloseCallbackDataPtr +virNewConnectCloseCallbackData(void) +{ + if (virDataTypesInitialize() < 0) + return NULL; + + return virObjectLockableNew(virConnectCloseCallbackDataClass); +} + void virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, virConnectPtr conn, virConnectCloseFunc cb, diff --git a/src/datatypes.h b/src/datatypes.h index 238317a9e3..92e686371b 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -421,9 +421,6 @@ struct _virConnect { virError err; /* the last error */ virErrorFunc handler; /* associated handler */ void *userData; /* the user data */ - - /* Per-connection close callback */ - virConnectCloseCallbackDataPtr closeCallback; }; /** @@ -640,6 +637,7 @@ virAdmConnectPtr virAdmConnectNew(void); virAdmServerPtr virAdmGetServer(virAdmConnectPtr conn, const char *name); +virConnectCloseCallbackDataPtr virNewConnectCloseCallbackData(void); void virConnectCloseCallbackDataRegister(virConnectCloseCallbackDataPtr close, virConnectPtr conn, virConnectCloseFunc cb, diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index ae2ec4d456..2cbd01bb20 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1212,6 +1212,16 @@ typedef int const char *password, unsigned int flags); +typedef int +(*virDrvConnectRegisterCloseCallback)(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb); + +typedef int +(*virDrvConnectUnregisterCloseCallback)(virConnectPtr conn, + virConnectCloseFunc cb); + typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; @@ -1443,6 +1453,8 @@ struct _virHypervisorDriver { virDrvDomainGetFSInfo domainGetFSInfo; virDrvDomainInterfaceAddresses domainInterfaceAddresses; virDrvDomainSetUserPassword domainSetUserPassword; + virDrvConnectRegisterCloseCallback connectRegisterCloseCallback; + virDrvConnectUnregisterCloseCallback connectUnregisterCloseCallback; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index b0597ee2fb..24277b71b7 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1217,14 +1217,9 @@ virConnectRegisterCloseCallback(virConnectPtr conn, virCheckConnectReturn(conn, -1); virCheckNonNullArgGoto(cb, error); - if (virConnectCloseCallbackDataGetCallback(conn->closeCallback) != NULL) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("A close callback is already registered")); + if (conn->driver->connectRegisterCloseCallback && + conn->driver->connectRegisterCloseCallback(conn, cb, opaque, freecb) < 0) goto error; - } - - virConnectCloseCallbackDataRegister(conn->closeCallback, conn, cb, - opaque, freecb); return 0; @@ -1257,13 +1252,9 @@ virConnectUnregisterCloseCallback(virConnectPtr conn, virCheckConnectReturn(conn, -1); virCheckNonNullArgGoto(cb, error); - if (virConnectCloseCallbackDataGetCallback(conn->closeCallback) != cb) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("A different callback was requested")); + if (conn->driver->connectUnregisterCloseCallback && + conn->driver->connectUnregisterCloseCallback(conn, cb) < 0) goto error; - } - - virConnectCloseCallbackDataUnregister(conn->closeCallback, cb); return 0; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e0cf33fdc3..b5b7063d96 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -96,6 +96,7 @@ struct private_data { bool serverEventFilter; /* Does server support modern event filtering */ virObjectEventStatePtr eventState; + virConnectCloseCallbackDataPtr closeCallback; }; enum { @@ -963,11 +964,13 @@ doRemoteOpen(virConnectPtr conn, goto failed; } - virObjectRef(conn->closeCallback); - + if (!(priv->closeCallback = virNewConnectCloseCallbackData())) + goto failed; + // ref on behalf of netclient + virObjectRef(priv->closeCallback); virNetClientSetCloseCallback(priv->client, remoteClientCloseFunc, - conn->closeCallback, virObjectFreeCallback); + priv->closeCallback, virObjectFreeCallback); if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM, REMOTE_PROTOCOL_VERSION, @@ -1097,6 +1100,8 @@ doRemoteOpen(virConnectPtr conn, virNetClientClose(priv->client); virObjectUnref(priv->client); priv->client = NULL; + virObjectUnref(priv->closeCallback); + priv->closeCallback = NULL; #ifdef WITH_GNUTLS virObjectUnref(priv->tls); priv->tls = NULL; @@ -1229,11 +1234,13 @@ doRemoteClose(virConnectPtr conn, struct private_data *priv) virNetClientSetCloseCallback(priv->client, NULL, - conn->closeCallback, virObjectFreeCallback); + priv->closeCallback, virObjectFreeCallback); virNetClientClose(priv->client); virObjectUnref(priv->client); priv->client = NULL; + virObjectUnref(priv->closeCallback); + priv->closeCallback = NULL; virObjectUnref(priv->remoteProgram); virObjectUnref(priv->lxcProgram); virObjectUnref(priv->qemuProgram); @@ -7887,6 +7894,56 @@ remoteDomainInterfaceAddresses(virDomainPtr dom, return rv; } +static int +remoteConnectRegisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb) +{ + struct private_data *priv = conn->privateData; + int ret = -1; + + remoteDriverLock(priv); + + if (virConnectCloseCallbackDataGetCallback(priv->closeCallback) != NULL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("A close callback is already registered")); + goto cleanup; + } + + virConnectCloseCallbackDataRegister(priv->closeCallback, conn, cb, + opaque, freecb); + ret = 0; + + cleanup: + remoteDriverUnlock(priv); + + return ret; +} + +static int +remoteConnectUnregisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb) +{ + struct private_data *priv = conn->privateData; + int ret = -1; + + remoteDriverLock(priv); + + if (virConnectCloseCallbackDataGetCallback(priv->closeCallback) != cb) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("A different callback was requested")); + goto cleanup; + } + + virConnectCloseCallbackDataUnregister(priv->closeCallback, cb); + ret = 0; + + cleanup: + remoteDriverUnlock(priv); + + return ret; +} static int remoteDomainRename(virDomainPtr dom, const char *new_name, unsigned int flags) @@ -8279,6 +8336,8 @@ static virHypervisorDriver hypervisor_driver = { .domainInterfaceAddresses = remoteDomainInterfaceAddresses, /* 1.2.14 */ .domainSetUserPassword = remoteDomainSetUserPassword, /* 1.2.16 */ .domainRename = remoteDomainRename, /* 1.2.19 */ + .connectRegisterCloseCallback = remoteConnectRegisterCloseCallback, /* 1.3.2 */ + .connectUnregisterCloseCallback = remoteConnectUnregisterCloseCallback, /* 1.3.2 */ }; static virNetworkDriver network_driver = {