From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> Define new virConnect{Register,Unregister}CloseCallback() public APIs which allows registering/unregistering a callback to be invoked when the connection to a hypervisor is closed. The callback is provided with the reason for the close, which may be 'error', 'eof' or 'keepalive'. Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> --- include/libvirt/libvirt.h.in | 49 +++++++++++++++---- src/datatypes.c | 3 ++ src/datatypes.h | 5 ++ src/libvirt.c | 111 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 + 5 files changed, 160 insertions(+), 10 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index fcef461..d9f0397 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -49,6 +49,24 @@ extern "C" { * defines VIR_ENUM_SENTINELS. Enumerations for bit values do not * have a *_LAST value, but additional bits may be defined. */ +/* + * virFreeCallback: + * @opaque: opaque user data provided at registration + * + * Type for a callback cleanup function to be paired with a callback. This + * function will be called as a final chance to clean up the @opaque + * registered with the primary callback, at the time when the primary + * callback is deregistered. + * + * It is forbidden to call any other libvirt APIs from an + * implementation of this callback, since it can be invoked + * from a context which is not re-entrant safe. Failure to + * abide by this requirement may lead to application deadlocks + * or crashes. + */ +typedef void (*virFreeCallback)(void *opaque); + + /** * virConnect: * @@ -1148,6 +1166,27 @@ int virConnectSetKeepAlive(virConnectPtr conn, int interval, unsigned int count); +typedef enum { + VIR_CONNECT_CLOSE_REASON_ERROR = 0, /* Misc I/O error */ + VIR_CONNECT_CLOSE_REASON_EOF = 1, /* End-of-file from server */ + VIR_CONNECT_CLOSE_REASON_KEEPALIVE = 2, /* Keepalive timer triggered */ + VIR_CONNECT_CLOSE_REASON_CLIENT = 3, /* Client requested it */ + +# ifdef VIR_ENUM_SENTINELS + VIR_CONNECT_CLOSE_REASON_LAST +# endif +} virConnectCloseReason; + +typedef void (*virConnectCloseFunc)(virConnectPtr conn, + int reason, + void *opaque); + +int virConnectRegisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb); +int virConnectUnregisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb); /* * Capabilities of the connection / driver. @@ -2863,16 +2902,6 @@ typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, int detail, void *opaque); -/* - * virFreeCallback: - * @opaque: opaque user data provided at registration - * - * Type for a domain event callback when the event is deregistered and - * need to be freed, @opaque is provided along with the callback at - * registration time - */ -typedef void (*virFreeCallback)(void *opaque); - int virConnectDomainEventRegister(virConnectPtr conn, virConnectDomainEventCallback cb, void *opaque, diff --git a/src/datatypes.c b/src/datatypes.c index 699c4a8..37a31d0 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -115,6 +115,9 @@ virReleaseConnect(virConnectPtr conn) { virMutexLock(&conn->lock); + if (conn->closeFreeCallback) + conn->closeFreeCallback(conn->closeOpaque); + virResetError(&conn->err); virURIFree(conn->uri); diff --git a/src/datatypes.h b/src/datatypes.h index 9ad2d01..8ac9171 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -187,6 +187,11 @@ struct _virConnect { virErrorFunc handler; /* associated handlet */ void *userData; /* the user data */ + /* Per-connection close callback */ + virConnectCloseFunc closeCallback; + void *closeOpaque; + virFreeCallback closeFreeCallback; + int refs; /* reference count */ }; diff --git a/src/libvirt.c b/src/libvirt.c index 8315b4f..9cfabc5 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -18613,6 +18613,117 @@ error: /** + * virConnectRegisterCloseCallback: + * @conn: pointer to connection object + * @cb: callback to invoke upon close + * @opaque: user data to pass to @cb + * @freecb: callback to free @opaque + * + * Registers a callback to be invoked when the connection + * is closed. This callback is invoked when there is any + * condition that causes the socket connection to the + * hypervisor to be closed. + * + * This function is only applicable to hypervisor drivers + * which maintain a persistent open connection. Drivers + * which open a new connection for every operation will + * not invoke this. + * + * The @freecb must not invoke any other libvirt public + * APIs, since it is not called from a re-entrant safe + * context. + * + * Returns 0 on success, -1 on error + */ +int virConnectRegisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb, + void *opaque, + virFreeCallback freecb) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + virMutexLock(&conn->lock); + + virCheckNonNullArgGoto(cb, error); + + if (conn->closeCallback) { + virLibConnError(VIR_ERR_OPERATION_INVALID, "%s", + _("A close callback is already registered")); + goto error; + } + + conn->closeCallback = cb; + conn->closeOpaque = opaque; + conn->closeFreeCallback = freecb; + + virMutexUnlock(&conn->lock); + + return 0; + +error: + virMutexUnlock(&conn->lock); + virDispatchError(NULL); + return -1; +} + +/** + * virConnectUnregisterCloseCallback: + * @conn: pointer to connection object + * @cb: pointer to the current registered callback + * + * Unregisters the callback previously set with the + * virConnectRegisterCloseCallback method. The callback + * will no longer received notifications when the connection + * closes. + * + * Returns 0 on success, -1 on error + */ +int virConnectUnregisterCloseCallback(virConnectPtr conn, + virConnectCloseFunc cb) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + virMutexLock(&conn->lock); + + virCheckNonNullArgGoto(cb, error); + + if (conn->closeCallback != cb) { + virLibConnError(VIR_ERR_OPERATION_INVALID, "%s", + _("A different callback was requested")); + goto error; + } + + conn->closeCallback = NULL; + if (conn->closeFreeCallback) + conn->closeFreeCallback(conn->closeOpaque); + + virMutexUnlock(&conn->lock); + + return 0; + +error: + virMutexUnlock(&conn->lock); + virDispatchError(NULL); + return -1; +} + +/** * virDomainSetBlockIoTune: * @dom: pointer to domain object * @disk: path to the block device, or device shorthand diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 1a8e58a..5004182 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -547,6 +547,8 @@ LIBVIRT_0.9.13 { LIBVIRT_0.9.14 { global: virDomainGetHostname; + virConnectRegisterCloseCallback; + virConnectUnregisterCloseCallback; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.10.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list