curl_version_info: add CURL_VERSION_THREADSAFE_INIT

This flag can be used to make sure that curl_global_init() is
thread-safe.

This can be useful for libraries that can't control what other
dependencies are doing with Curl.

Closes #8680
This commit is contained in:
Thomas Guillem 2022-04-05 16:00:37 +02:00 committed by Daniel Stenberg
parent 23af112f55
commit 2ed1012564
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
10 changed files with 141 additions and 4 deletions

View File

@ -4258,6 +4258,23 @@ if test ${ac_cv_sizeof_curl_off_t} -gt 4; then
fi
fi
if test "$tst_atomic" = "yes"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe-init"
else
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#include <windows.h>
]],[[
#if (WINVER < 0x600) && (_WIN32_WINNT < 0x600)
#error
#endif
]])
],[
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe-init"
],[
])
fi
dnl replace spaces with newlines
dnl sort the lines
dnl replace the newlines back to spaces

View File

@ -204,6 +204,9 @@ libcurl was built with support for SSPI. This is only available on Windows and
makes libcurl use Windows-provided functions for Kerberos, NTLM, SPNEGO and
Digest authentication. It also allows libcurl to use the current user
credentials without the app having to pass them on. (Added in 7.13.2)
.IP CURL_VERSION_THREADSAFE_INIT
libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect
curl initialisation. (Added in 7.84.0)
.IP CURL_VERSION_TLSAUTH_SRP
libcurl was built with support for TLS-SRP (in one or more of the built-in TLS
backends). (Added in 7.21.4)

View File

@ -172,6 +172,7 @@ CURL_VERSION_PSL 7.47.0
CURL_VERSION_SPNEGO 7.10.8
CURL_VERSION_SSL 7.10
CURL_VERSION_SSPI 7.13.2
CURL_VERSION_THREADSAFE_INIT 7.84.0
CURL_VERSION_TLSAUTH_SRP 7.21.4
CURL_VERSION_UNICODE 7.72.0
CURL_VERSION_UNIX_SOCKETS 7.40.0

View File

@ -2607,8 +2607,10 @@ CURL_EXTERN void curl_free(void *p);
*
* curl_global_init() should be invoked exactly once for each application that
* uses libcurl and before any call of other libcurl functions.
*
* This function is not thread-safe!
* This function is thread-safe if CURL_VERSION_THREADSAFE_INIT is set in the
* curl_version_info_data.features flag (fetch by curl_version_info()).
*/
CURL_EXTERN CURLcode curl_global_init(long flags);
@ -3025,6 +3027,8 @@ typedef struct curl_version_info_data curl_version_info_data;
#define CURL_VERSION_UNICODE (1<<27) /* Unicode support on Windows */
#define CURL_VERSION_HSTS (1<<28) /* HSTS is supported */
#define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */
#define CURL_VERSION_THREADSAFE_INIT (1<<30) /* curl_global_init/cleanup() are
thread-safe */
/*
* NAME curl_version_info()

View File

@ -29,6 +29,7 @@
#include "vssh/ssh.h"
#include "quic.h"
#include "curl_printf.h"
#include "easy_lock.h"
#ifdef USE_ARES
# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
@ -450,6 +451,9 @@ static curl_version_info_data version_info = {
#endif
#if defined(USE_GSASL)
| CURL_VERSION_GSASL
#endif
#if defined(GLOBAL_INIT_IS_THREADSAFE)
| CURL_VERSION_THREADSAFE_INIT
#endif
,
NULL, /* ssl_version */

View File

@ -148,6 +148,8 @@
d c X'10000000'
d CURL_VERSION_GSASL...
d c X'20000000'
d CURL_VERSION_THREADSAFE_INIT...
d c X'40000000'
*
d CURL_HTTPPOST_FILENAME...
d c X'00000001'

View File

@ -110,6 +110,7 @@ static const struct feat feats[] = {
{"alt-svc", CURL_VERSION_ALTSVC},
{"HSTS", CURL_VERSION_HSTS},
{"gsasl", CURL_VERSION_GSASL},
{"threadsafe-init",CURL_VERSION_THREADSAFE_INIT},
};
static void print_category(curlhelp_t category)

View File

@ -245,4 +245,4 @@ test2200 test2201 test2202 test2203 test2204 test2205 \
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \
test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \
test3024 test3025
test3024 test3025 test3026

View File

@ -63,7 +63,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib1915 lib1916 lib1917 lib1918 lib1919 \
lib1933 lib1934 lib1935 lib1936 lib1937 lib1938 lib1939 lib1940 \
lib1945 lib1946 \
lib3010 lib3025
lib3010 lib3025 lib3026
chkdecimalpoint_SOURCES = chkdecimalpoint.c ../../lib/mprintf.c \
../../lib/curl_ctype.c ../../lib/dynbuf.c ../../lib/strdup.c
@ -747,3 +747,7 @@ lib3010_CPPFLAGS = $(AM_CPPFLAGS)
lib3025_SOURCES = lib3025.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib3025_LDADD = $(TESTUTIL_LIBS)
lib3025_CPPFLAGS = $(AM_CPPFLAGS)
lib3026_SOURCES = lib3026.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib3026_LDADD = $(TESTUTIL_LIBS)
lib3026_CPPFLAGS = $(AM_CPPFLAGS)

101
tests/libtest/lib3026.c Normal file
View File

@ -0,0 +1,101 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "test.h"
#include "testutil.h"
#include "warnless.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 1000
static void *run_thread(void *ptr)
{
CURLcode *result = ptr;
*result = curl_global_init(CURL_GLOBAL_ALL);
if(*result == CURLE_OK)
curl_global_cleanup();
return NULL;
}
int test(char *URL)
{
CURLcode results[NUM_THREADS];
pthread_t tids[NUM_THREADS];
unsigned tid_count = NUM_THREADS, i;
int test_failure = 0;
curl_version_info_data *ver;
(void) URL;
ver = curl_version_info(CURLVERSION_NOW);
if((ver->features & CURL_VERSION_THREADSAFE_INIT) == 0) {
fprintf(stderr, "%s:%d Have pthread but the "
"CURL_VERSION_THREADSAFE_INIT feature flag is not set\n",
__FILE__, __LINE__);
return -1;
}
for(i = 0; i < tid_count; i++) {
int res = pthread_create(&tids[i], NULL, run_thread, &results[i]);
if(res) {
fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n",
__FILE__, __LINE__, res);
tid_count = i;
test_failure = -1;
goto cleanup;
}
}
cleanup:
for(i = 0; i < tid_count; i++) {
pthread_join(tids[i], NULL);
if(results[i] != CURLE_OK) {
fprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed,"
"with code %d (%s)\n", __FILE__, __LINE__,
i, (int) results[i], curl_easy_strerror(results[i]));
test_failure = -1;
}
}
return test_failure;
}
#else /* without pthread, this test doesn't work */
int test(char *URL)
{
curl_version_info_data *ver;
(void)URL;
ver = curl_version_info(CURLVERSION_NOW);
if((ver->features & CURL_VERSION_THREADSAFE_INIT) != 0) {
fprintf(stderr, "%s:%d No pthread but the "
"CURL_VERSION_THREADSAFE_INIT feature flag is set\n",
__FILE__, __LINE__);
return -1;
}
return 0;
}
#endif