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 "test.h" 25 26#include "testutil.h" 27#include "warnless.h" 28 29#define NUM_THREADS 100 30 31#ifdef _WIN32 32#ifdef _WIN32_WCE 33static DWORD WINAPI run_thread(LPVOID ptr) 34#else 35#include <process.h> 36static unsigned int WINAPI run_thread(void *ptr) 37#endif 38{ 39 CURLcode *result = ptr; 40 41 *result = curl_global_init(CURL_GLOBAL_ALL); 42 if(*result == CURLE_OK) 43 curl_global_cleanup(); 44 45 return 0; 46} 47 48int test(char *URL) 49{ 50#ifdef _WIN32_WCE 51 typedef HANDLE curl_win_thread_handle_t; 52#else 53 typedef uintptr_t curl_win_thread_handle_t; 54#endif 55 CURLcode results[NUM_THREADS]; 56 curl_win_thread_handle_t ths[NUM_THREADS]; 57 unsigned tid_count = NUM_THREADS, i; 58 int test_failure = 0; 59 curl_version_info_data *ver; 60 (void) URL; 61 62 ver = curl_version_info(CURLVERSION_NOW); 63 if((ver->features & CURL_VERSION_THREADSAFE) == 0) { 64 fprintf(stderr, "%s:%d On Windows but the " 65 "CURL_VERSION_THREADSAFE feature flag is not set\n", 66 __FILE__, __LINE__); 67 return -1; 68 } 69 70 /* On Windows libcurl global init/cleanup calls LoadLibrary/FreeLibrary for 71 secur32.dll and iphlpapi.dll. Here we load them beforehand so that when 72 libcurl calls LoadLibrary/FreeLibrary it only increases/decreases the 73 library's refcount rather than actually loading/unloading the library, 74 which would affect the test runtime. */ 75 (void)win32_load_system_library(TEXT("secur32.dll")); 76 (void)win32_load_system_library(TEXT("iphlpapi.dll")); 77 78 for(i = 0; i < tid_count; i++) { 79 curl_win_thread_handle_t th; 80 results[i] = CURL_LAST; /* initialize with invalid value */ 81#ifdef _WIN32_WCE 82 th = CreateThread(NULL, 0, run_thread, &results[i], 0, NULL); 83#else 84 th = _beginthreadex(NULL, 0, run_thread, &results[i], 0, NULL); 85#endif 86 if(!th) { 87 fprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n", 88 __FILE__, __LINE__, GetLastError()); 89 tid_count = i; 90 test_failure = -1; 91 goto cleanup; 92 } 93 ths[i] = th; 94 } 95 96cleanup: 97 for(i = 0; i < tid_count; i++) { 98 WaitForSingleObject((HANDLE)ths[i], INFINITE); 99 CloseHandle((HANDLE)ths[i]); 100 if(results[i] != CURLE_OK) { 101 fprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," 102 "with code %d (%s)\n", __FILE__, __LINE__, 103 i, (int) results[i], curl_easy_strerror(results[i])); 104 test_failure = -1; 105 } 106 } 107 108 return test_failure; 109} 110 111#elif defined(HAVE_PTHREAD_H) 112#include <pthread.h> 113#include <unistd.h> 114 115static void *run_thread(void *ptr) 116{ 117 CURLcode *result = ptr; 118 119 *result = curl_global_init(CURL_GLOBAL_ALL); 120 if(*result == CURLE_OK) 121 curl_global_cleanup(); 122 123 return NULL; 124} 125 126int test(char *URL) 127{ 128 CURLcode results[NUM_THREADS]; 129 pthread_t tids[NUM_THREADS]; 130 unsigned tid_count = NUM_THREADS, i; 131 int test_failure = 0; 132 curl_version_info_data *ver; 133 (void) URL; 134 135 ver = curl_version_info(CURLVERSION_NOW); 136 if((ver->features & CURL_VERSION_THREADSAFE) == 0) { 137 fprintf(stderr, "%s:%d Have pthread but the " 138 "CURL_VERSION_THREADSAFE feature flag is not set\n", 139 __FILE__, __LINE__); 140 return -1; 141 } 142 143 for(i = 0; i < tid_count; i++) { 144 int res; 145 results[i] = CURL_LAST; /* initialize with invalid value */ 146 res = pthread_create(&tids[i], NULL, run_thread, &results[i]); 147 if(res) { 148 fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n", 149 __FILE__, __LINE__, res); 150 tid_count = i; 151 test_failure = -1; 152 goto cleanup; 153 } 154 } 155 156cleanup: 157 for(i = 0; i < tid_count; i++) { 158 pthread_join(tids[i], NULL); 159 if(results[i] != CURLE_OK) { 160 fprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," 161 "with code %d (%s)\n", __FILE__, __LINE__, 162 i, (int) results[i], curl_easy_strerror(results[i])); 163 test_failure = -1; 164 } 165 } 166 167 return test_failure; 168} 169 170#else /* without pthread or Windows, this test doesn't work */ 171int test(char *URL) 172{ 173 curl_version_info_data *ver; 174 (void)URL; 175 176 ver = curl_version_info(CURLVERSION_NOW); 177 if((ver->features & CURL_VERSION_THREADSAFE) != 0) { 178 fprintf(stderr, "%s:%d No pthread but the " 179 "CURL_VERSION_THREADSAFE feature flag is set\n", 180 __FILE__, __LINE__); 181 return -1; 182 } 183 return 0; 184} 185#endif 186