xref: /third_party/curl/tests/libtest/lib3026.c (revision 13498266)
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