[libvirt] [PATCH] esx: Add a wrapper for shared CURL handles

Matthias Bolte matthias.bolte at googlemail.com
Sun Apr 10 15:17:24 UTC 2011


To be used to share a CURL handle between multiple threads in the
upcoming domain event support.
---
 src/esx/esx_vi.c |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/esx/esx_vi.h |   19 ++++++
 2 files changed, 195 insertions(+), 0 deletions(-)

diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 2fd09cd..84ff2e2 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -85,6 +85,16 @@ ESX_VI__TEMPLATE__ALLOC(CURL)
 /* esxVI_CURL_Free */
 ESX_VI__TEMPLATE__FREE(CURL,
 {
+    esxVI_SharedCURL *shared = item->shared;
+
+    if (shared != NULL) {
+        esxVI_SharedCURL_Remove(shared, item);
+
+        if (shared->count == 0) {
+            esxVI_SharedCURL_Free(&shared);
+        }
+    }
+
     if (item->handle != NULL) {
         curl_easy_cleanup(item->handle);
     }
@@ -418,6 +428,172 @@ esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * SharedCURL
+ */
+
+static void
+esxVI_SharedCURL_Lock(CURL *handle ATTRIBUTE_UNUSED, curl_lock_data data,
+                      curl_lock_access access_ ATTRIBUTE_UNUSED, void *userptr)
+{
+    int i;
+    esxVI_SharedCURL *shared = userptr;
+
+    switch (data) {
+      case CURL_LOCK_DATA_SHARE:
+        i = 0;
+        break;
+
+      case CURL_LOCK_DATA_COOKIE:
+        i = 1;
+        break;
+
+      case CURL_LOCK_DATA_DNS:
+        i = 2;
+        break;
+
+      default:
+        VIR_ERROR(_("Trying to lock unknown SharedCURL lock %d"), (int)data);
+        return;
+    }
+
+    virMutexLock(&shared->locks[i]);
+}
+
+static void
+esxVI_SharedCURL_Unlock(CURL *handle ATTRIBUTE_UNUSED, curl_lock_data data,
+                        void *userptr)
+{
+    int i;
+    esxVI_SharedCURL *shared = userptr;
+
+    switch (data) {
+      case CURL_LOCK_DATA_SHARE:
+        i = 0;
+        break;
+
+      case CURL_LOCK_DATA_COOKIE:
+        i = 1;
+        break;
+
+      case CURL_LOCK_DATA_DNS:
+        i = 2;
+        break;
+
+      default:
+        VIR_ERROR(_("Trying to unlock unknown SharedCURL lock %d"), (int)data);
+        return;
+    }
+
+    virMutexUnlock(&shared->locks[i]);
+}
+
+/* esxVI_SharedCURL_Alloc */
+ESX_VI__TEMPLATE__ALLOC(SharedCURL)
+
+/* esxVI_SharedCURL_Free */
+ESX_VI__TEMPLATE__FREE(SharedCURL,
+{
+    int i;
+
+    if (item->count > 0) {
+        /* Better leak than crash */
+        VIR_ERROR0(_("Trying to free SharedCURL object that is still in use"));
+        return;
+    }
+
+    if (item->handle != NULL) {
+        curl_share_cleanup(item->handle);
+    }
+
+    for (i = 0; i < ARRAY_CARDINALITY(item->locks); ++i) {
+        virMutexDestroy(&item->locks[i]);
+    }
+})
+
+int
+esxVI_SharedCURL_Add(esxVI_SharedCURL *shared, esxVI_CURL *curl)
+{
+    int i;
+
+    if (curl->handle == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Cannot share uninitialized CURL handle"));
+        return -1;
+    }
+
+    if (curl->shared != NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Cannot share CURL handle that is already shared"));
+        return -1;
+    }
+
+    if (shared->handle == NULL) {
+        shared->handle = curl_share_init();
+
+        if (shared->handle == NULL) {
+            ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                         _("Could not initialize CURL (share)"));
+            return -1;
+        }
+
+        curl_share_setopt(shared->handle, CURLSHOPT_LOCKFUNC,
+                          esxVI_SharedCURL_Lock);
+        curl_share_setopt(shared->handle, CURLSHOPT_UNLOCKFUNC,
+                          esxVI_SharedCURL_Unlock);
+        curl_share_setopt(shared->handle, CURLSHOPT_USERDATA, shared);
+        curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
+                          CURL_LOCK_DATA_COOKIE);
+        curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
+                          CURL_LOCK_DATA_DNS);
+
+        for (i = 0; i < ARRAY_CARDINALITY(shared->locks); ++i) {
+            if (virMutexInit(&shared->locks[i]) < 0) {
+                ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("Could not initialize a CURL (share) mutex"));
+                return -1;
+            }
+        }
+    }
+
+    curl_easy_setopt(curl->handle, CURLOPT_SHARE, shared->handle);
+
+    curl->shared = shared;
+    ++shared->count;
+
+    return 0;
+}
+
+int
+esxVI_SharedCURL_Remove(esxVI_SharedCURL *shared, esxVI_CURL *curl)
+{
+    if (curl->handle == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Cannot unshare uninitialized CURL handle"));
+        return -1;
+    }
+
+    if (curl->shared == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Cannot unshare CURL handle that is not shared"));
+        return -1;
+    }
+
+    if (curl->shared != shared) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (share) mismatch"));
+        return -1;
+    }
+
+    curl_easy_setopt(curl->handle, CURLOPT_SHARE, NULL);
+
+    curl->shared = NULL;
+    --shared->count;
+
+    return 0;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Context
  */
 
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 57788ac..560b2a6 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -83,6 +83,7 @@ typedef enum _esxVI_ProductVersion esxVI_ProductVersion;
 typedef enum _esxVI_Occurrence esxVI_Occurrence;
 typedef struct _esxVI_ParsedHostCpuIdInfo esxVI_ParsedHostCpuIdInfo;
 typedef struct _esxVI_CURL esxVI_CURL;
+typedef struct _esxVI_SharedCURL esxVI_SharedCURL;
 typedef struct _esxVI_Context esxVI_Context;
 typedef struct _esxVI_Response esxVI_Response;
 typedef struct _esxVI_Enumeration esxVI_Enumeration;
@@ -151,6 +152,7 @@ struct _esxVI_CURL {
     virMutex lock;
     struct curl_slist *headers;
     char error[CURL_ERROR_SIZE];
+    esxVI_SharedCURL *shared;
 };
 
 int esxVI_CURL_Alloc(esxVI_CURL **curl);
@@ -162,6 +164,23 @@ int esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content);
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * SharedCURL
+ */
+
+struct _esxVI_SharedCURL {
+    CURLSH *handle;
+    virMutex locks[3]; /* share, cookie, dns */
+    size_t count;
+};
+
+int esxVI_SharedCURL_Alloc(esxVI_SharedCURL **shared);
+void esxVI_SharedCURL_Free(esxVI_SharedCURL **shared);
+int esxVI_SharedCURL_Add(esxVI_SharedCURL *shared, esxVI_CURL *curl);
+int esxVI_SharedCURL_Remove(esxVI_SharedCURL *shared, esxVI_CURL *curl);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Context
  */
 
-- 
1.7.0.4




More information about the libvir-list mailing list