]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add public API to register a callback to be invoked on connection close
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 19 Jul 2012 10:01:07 +0000 (11:01 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 30 Jul 2012 09:08:40 +0000 (10:08 +0100)
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', 'client'
or 'keepalive'.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
include/libvirt/libvirt.h.in
src/datatypes.c
src/datatypes.h
src/libvirt.c
src/libvirt_public.syms

index 71e41e8169e7334faa9f2cf9c186e36fd02b1fec..d21d029bf28a1cb48f08ffcdb00eb87e913994d4 100644 (file)
@@ -61,6 +61,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:
  *
@@ -1160,6 +1178,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.
@@ -2875,16 +2914,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,
index 77dca6f5b1af8a5970df32364f19f5fbbbcfe446..f1f6e611e585ae29a8c0297947eed1c6882196bd 100644 (file)
@@ -115,6 +115,9 @@ virReleaseConnect(virConnectPtr conn) {
 
     virMutexLock(&conn->lock);
 
+    if (conn->closeFreeCallback)
+        conn->closeFreeCallback(conn->closeOpaque);
+
     virResetError(&conn->err);
 
     virURIFree(conn->uri);
index 9ad2d017288c218e252b30e7e4e8ee6c4ea5f454..8ac9171e9f91c84cd13949239dee5988da9d1ff9 100644 (file)
@@ -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 */
 };
 
index 93c10942d3718d092fa4ae4159f7e798e560f56e..e7bab13f0490dec3e4194f8a569cdcc39b8104de 100644 (file)
@@ -18624,6 +18624,120 @@ 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 receive notifications when the connection
+ * closes. If a virFreeCallback was provided at time of
+ * registration, it will be invoked
+ *
+ * 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);
+    conn->closeFreeCallback = NULL;
+    conn->closeOpaque = NULL;
+
+    virMutexUnlock(&conn->lock);
+
+    return 0;
+
+error:
+    virMutexUnlock(&conn->lock);
+    virDispatchError(NULL);
+    return -1;
+}
+
 /**
  * virDomainSetBlockIoTune:
  * @dom: pointer to domain object
index 1a8e58aed280d86005b9a4dc231c108810192a67..500418276325364ace17993fe777587bcc383b45 100644 (file)
@@ -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 ....