xref: /curl/tests/libtest/lib3026.c (revision bc2f72b9)
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 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
run_thread(LPVOID ptr)33 static DWORD WINAPI run_thread(LPVOID ptr)
34 #else
35 #include <process.h>
36 static 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 
test(char * URL)48 CURLcode test(char *URL)
49 {
50 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
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 (CURLcode)-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 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
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 
96 cleanup:
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 (CURLcode)test_failure;
109 }
110 
111 #elif defined(HAVE_PTHREAD_H)
112 #include <pthread.h>
113 #include <unistd.h>
114 
run_thread(void * ptr)115 static 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 
test(char * URL)126 CURLcode test(char *URL)
127 {
128   CURLcode results[NUM_THREADS];
129   pthread_t tids[NUM_THREADS];
130   unsigned tid_count = NUM_THREADS, i;
131   CURLcode test_failure = CURLE_OK;
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 (CURLcode)-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 = (CURLcode)-1;
152       goto cleanup;
153     }
154   }
155 
156 cleanup:
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 = (CURLcode)-1;
164     }
165   }
166 
167   return test_failure;
168 }
169 
170 #else /* without pthread or Windows, this test doesn't work */
test(char * URL)171 CURLcode 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 (CURLcode)-1;
182   }
183   return CURLE_OK;
184 }
185 #endif
186