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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list