Skip to content

Commit

Permalink
curl_version_info: add CURL_VERSION_THREADSAFE_INIT
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tguillem authored and bagder committed Jun 7, 2022
1 parent 23af112 commit 2ed1012
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 4 deletions.
17 changes: 17 additions & 0 deletions configure.ac
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions docs/libcurl/curl_version_info.3
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions include/curl/curl.h
Expand Up @@ -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);

Expand Down Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions lib/version.c
Expand Up @@ -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) && \
Expand Down Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions packages/OS400/curl.inc.in
Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions src/tool_help.c
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion tests/data/Makefile.inc
Expand Up @@ -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
6 changes: 5 additions & 1 deletion tests/libtest/Makefile.inc
Expand Up @@ -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
Expand Down Expand Up @@ -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 changes: 101 additions & 0 deletions tests/libtest/lib3026.c
@@ -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

0 comments on commit 2ed1012

Please sign in to comment.