lib3207.c (6151B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "first.h" 25 26 #include "memdebug.h" 27 28 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) 29 #if defined(USE_THREADS_POSIX) 30 #include <pthread.h> 31 #endif 32 #include "curl_threads.h" 33 #endif 34 35 #define CAINFO libtest_arg2 36 #define THREAD_SIZE 16 37 #define PER_THREAD_SIZE 8 38 39 struct Ctx { 40 const char *URL; 41 CURLSH *share; 42 CURLcode result; 43 size_t thread_id; 44 struct curl_slist *contents; 45 }; 46 47 static size_t write_memory_callback(char *contents, size_t size, 48 size_t nmemb, void *userp) 49 { 50 /* append the data to contents */ 51 size_t realsize = size * nmemb; 52 struct Ctx *mem = (struct Ctx *)userp; 53 char *data = (char *)malloc(realsize + 1); 54 struct curl_slist *item_append = NULL; 55 if(!data) { 56 curl_mprintf("not enough memory (malloc returned NULL)\n"); 57 return 0; 58 } 59 memcpy(data, contents, realsize); 60 data[realsize] = '\0'; 61 item_append = curl_slist_append(mem->contents, data); 62 free(data); 63 if(item_append) { 64 mem->contents = item_append; 65 } 66 else { 67 curl_mprintf("not enough memory (curl_slist_append returned NULL)\n"); 68 return 0; 69 } 70 return realsize; 71 } 72 73 static 74 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) 75 #if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) 76 DWORD 77 #else 78 unsigned int 79 #endif 80 CURL_STDCALL 81 #else 82 unsigned int 83 #endif 84 test_thread(void *ptr) 85 { 86 struct Ctx *ctx = (struct Ctx *)ptr; 87 CURLcode res = CURLE_OK; 88 89 int i; 90 91 /* Loop the transfer and cleanup the handle properly every lap. This will 92 still reuse ssl session since the pool is in the shared object! */ 93 for(i = 0; i < PER_THREAD_SIZE; i++) { 94 CURL *curl = curl_easy_init(); 95 if(curl) { 96 curl_easy_setopt(curl, CURLOPT_URL, (char *)CURL_UNCONST(ctx->URL)); 97 98 /* use the share object */ 99 curl_easy_setopt(curl, CURLOPT_SHARE, ctx->share); 100 curl_easy_setopt(curl, CURLOPT_CAINFO, CAINFO); 101 102 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); 103 curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); 104 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 105 106 /* Perform the request, res will get the return code */ 107 res = curl_easy_perform(curl); 108 109 /* always cleanup */ 110 curl_easy_cleanup(curl); 111 /* Check for errors */ 112 if(res != CURLE_OK) { 113 curl_mfprintf(stderr, "curl_easy_perform() failed: %s\n", 114 curl_easy_strerror(res)); 115 goto test_cleanup; 116 } 117 } 118 } 119 120 test_cleanup: 121 ctx->result = res; 122 return 0; 123 } 124 125 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) 126 127 static void t3207_test_lock(CURL *handle, curl_lock_data data, 128 curl_lock_access laccess, void *useptr) 129 { 130 curl_mutex_t *mutexes = (curl_mutex_t*) useptr; 131 (void)handle; 132 (void)laccess; 133 Curl_mutex_acquire(&mutexes[data]); 134 } 135 136 static void t3207_test_unlock(CURL *handle, curl_lock_data data, void *useptr) 137 { 138 curl_mutex_t *mutexes = (curl_mutex_t*) useptr; 139 (void)handle; 140 Curl_mutex_release(&mutexes[data]); 141 } 142 143 static void execute(CURLSH *share, struct Ctx *ctx) 144 { 145 size_t i; 146 curl_mutex_t mutexes[CURL_LOCK_DATA_LAST - 1]; 147 curl_thread_t thread[THREAD_SIZE]; 148 for(i = 0; i < CURL_ARRAYSIZE(mutexes); i++) { 149 Curl_mutex_init(&mutexes[i]); 150 } 151 curl_share_setopt(share, CURLSHOPT_LOCKFUNC, t3207_test_lock); 152 curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, t3207_test_unlock); 153 curl_share_setopt(share, CURLSHOPT_USERDATA, (void *)mutexes); 154 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); 155 156 for(i = 0; i < CURL_ARRAYSIZE(thread); i++) { 157 thread[i] = Curl_thread_create(test_thread, (void *)&ctx[i]); 158 } 159 for(i = 0; i < CURL_ARRAYSIZE(thread); i++) { 160 if(thread[i]) { 161 Curl_thread_join(&thread[i]); 162 Curl_thread_destroy(&thread[i]); 163 } 164 } 165 curl_share_setopt(share, CURLSHOPT_LOCKFUNC, NULL); 166 curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, NULL); 167 for(i = 0; i < CURL_ARRAYSIZE(mutexes); i++) { 168 Curl_mutex_destroy(&mutexes[i]); 169 } 170 } 171 172 #else /* without pthread, run serially */ 173 174 static void execute(CURLSH *share, struct Ctx *ctx) 175 { 176 size_t i; 177 (void) share; 178 for(i = 0; i < THREAD_SIZE; i++) { 179 test_thread((void *)&ctx[i]); 180 } 181 } 182 183 #endif 184 185 static CURLcode test_lib3207(char *URL) 186 { 187 CURLcode res = CURLE_OK; 188 size_t i; 189 CURLSH* share; 190 struct Ctx ctx[THREAD_SIZE]; 191 192 curl_global_init(CURL_GLOBAL_ALL); 193 194 share = curl_share_init(); 195 if(!share) { 196 curl_mfprintf(stderr, "curl_share_init() failed\n"); 197 goto test_cleanup; 198 } 199 200 for(i = 0; i < CURL_ARRAYSIZE(ctx); i++) { 201 ctx[i].share = share; 202 ctx[i].URL = URL; 203 ctx[i].thread_id = i; 204 ctx[i].result = CURLE_OK; 205 ctx[i].contents = NULL; 206 } 207 208 execute(share, ctx); 209 210 for(i = 0; i < CURL_ARRAYSIZE(ctx); i++) { 211 if(ctx[i].result) { 212 res = ctx[i].result; 213 } 214 else { 215 struct curl_slist *item = ctx[i].contents; 216 while(item) { 217 curl_mprintf("%s", item->data); 218 item = item->next; 219 } 220 } 221 curl_slist_free_all(ctx[i].contents); 222 } 223 224 test_cleanup: 225 if(share) 226 curl_share_cleanup(share); 227 curl_global_cleanup(); 228 return res; 229 }