mirror of
https://github.com/curl/curl.git
synced 2024-12-09 06:30:06 +08:00
lib: make curl_global_init() threadsafe when possible
Use a posix pthread or a Windows SRWLOCK to lock curl_global_init*() and curl_global_cleanup(). Closes #8680
This commit is contained in:
parent
134963a5ef
commit
23af112f55
@ -118,6 +118,7 @@ AC_SUBST(libext)
|
||||
dnl figure out the libcurl version
|
||||
CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/include/curl/curlver.h`
|
||||
XC_CHECK_PROG_CC
|
||||
CURL_ATOMIC
|
||||
|
||||
dnl for --enable-code-coverage
|
||||
CURL_COVERAGE
|
||||
@ -3444,6 +3445,7 @@ AC_CHECK_FUNCS([fnmatch \
|
||||
if_nametoindex \
|
||||
mach_absolute_time \
|
||||
pipe \
|
||||
sched_yield \
|
||||
setlocale \
|
||||
setmode \
|
||||
setrlimit \
|
||||
|
@ -262,6 +262,7 @@ LIB_HFILES = \
|
||||
doh.h \
|
||||
dotdot.h \
|
||||
dynbuf.h \
|
||||
easy_lock.h \
|
||||
easyif.h \
|
||||
easyoptions.h \
|
||||
escape.h \
|
||||
|
54
lib/easy.c
54
lib/easy.c
@ -84,11 +84,25 @@
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
#include "easy_lock.h"
|
||||
|
||||
/* true globals -- for curl_global_init() and curl_global_cleanup() */
|
||||
static unsigned int initialized;
|
||||
static long init_flags;
|
||||
|
||||
#ifdef GLOBAL_INIT_IS_THREADSAFE
|
||||
|
||||
static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
|
||||
#define global_init_lock() curl_simple_lock_lock(&s_lock)
|
||||
#define global_init_unlock() curl_simple_lock_unlock(&s_lock)
|
||||
|
||||
#else
|
||||
|
||||
#define global_init_lock()
|
||||
#define global_init_unlock()
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* strdup (and other memory functions) is redefined in complicated
|
||||
* ways, but at this point it must be defined as the system-supplied strdup
|
||||
@ -207,7 +221,14 @@ static CURLcode global_init(long flags, bool memoryfuncs)
|
||||
*/
|
||||
CURLcode curl_global_init(long flags)
|
||||
{
|
||||
return global_init(flags, TRUE);
|
||||
CURLcode result;
|
||||
global_init_lock();
|
||||
|
||||
result = global_init(flags, TRUE);
|
||||
|
||||
global_init_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -218,15 +239,20 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
|
||||
curl_free_callback f, curl_realloc_callback r,
|
||||
curl_strdup_callback s, curl_calloc_callback c)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
/* Invalid input, return immediately */
|
||||
if(!m || !f || !r || !s || !c)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
global_init_lock();
|
||||
|
||||
if(initialized) {
|
||||
/* Already initialized, don't do it again, but bump the variable anyway to
|
||||
work like curl_global_init() and require the same amount of cleanup
|
||||
calls. */
|
||||
initialized++;
|
||||
global_init_unlock();
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -239,7 +265,11 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
|
||||
Curl_ccalloc = c;
|
||||
|
||||
/* Call the actual init function, but without setting */
|
||||
return global_init(flags, FALSE);
|
||||
result = global_init(flags, FALSE);
|
||||
|
||||
global_init_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,11 +278,17 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
|
||||
*/
|
||||
void curl_global_cleanup(void)
|
||||
{
|
||||
if(!initialized)
|
||||
return;
|
||||
global_init_lock();
|
||||
|
||||
if(--initialized)
|
||||
if(!initialized) {
|
||||
global_init_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if(--initialized) {
|
||||
global_init_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
Curl_ssl_cleanup();
|
||||
Curl_resolver_global_cleanup();
|
||||
@ -273,6 +309,8 @@ void curl_global_cleanup(void)
|
||||
#endif
|
||||
|
||||
init_flags = 0;
|
||||
|
||||
global_init_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -285,14 +323,18 @@ struct Curl_easy *curl_easy_init(void)
|
||||
struct Curl_easy *data;
|
||||
|
||||
/* Make sure we inited the global SSL stuff */
|
||||
global_init_lock();
|
||||
|
||||
if(!initialized) {
|
||||
result = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
result = global_init(CURL_GLOBAL_DEFAULT, TRUE);
|
||||
if(result) {
|
||||
/* something in the global init failed, return nothing */
|
||||
DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
|
||||
global_init_unlock();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
global_init_unlock();
|
||||
|
||||
/* We use curl_open() with undefined URL so far */
|
||||
result = Curl_open(&data);
|
||||
|
69
lib/easy_lock.h
Normal file
69
lib/easy_lock.h
Normal file
@ -0,0 +1,69 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 "curl_setup.h"
|
||||
|
||||
#define GLOBAL_INIT_IS_THREADSAFE
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
|
||||
|
||||
#define curl_simple_lock SRWLOCK
|
||||
#define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT
|
||||
|
||||
#define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m)
|
||||
#define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m)
|
||||
|
||||
#elif defined (HAVE_ATOMIC)
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define curl_simple_lock atomic_bool
|
||||
#define CURL_SIMPLE_LOCK_INIT ATOMIC_VAR_INIT(false)
|
||||
|
||||
static inline void curl_simple_lock_lock(curl_simple_lock *lock)
|
||||
{
|
||||
for(;;) {
|
||||
if(!atomic_exchange_explicit(lock, true, memory_order_acquire))
|
||||
break;
|
||||
/* Reduce cache coherency traffic */
|
||||
while(atomic_load_explicit(lock, memory_order_relaxed)) {
|
||||
/* Reduce load (not mandatory) */
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__builtin_ia32_pause();
|
||||
#elif defined(__aarch64__)
|
||||
asm volatile("yield" ::: "memory");
|
||||
#elif defined(HAVE_SCHED_YIELD)
|
||||
sched_yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void curl_simple_lock_unlock(curl_simple_lock *lock)
|
||||
{
|
||||
atomic_store_explicit(lock, false, memory_order_release);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#undef GLOBAL_INIT_IS_THREADSAFE
|
||||
|
||||
#endif
|
@ -6566,3 +6566,26 @@ AC_DEFUN([CURL_COVERAGE],[
|
||||
LIBS="$LIBS -lgcov"
|
||||
fi
|
||||
])
|
||||
|
||||
dnl CURL_ATOMIC
|
||||
dnl --------------------------------------------------
|
||||
dnl Check if _Atomic works
|
||||
dnl
|
||||
AC_DEFUN([CURL_ATOMIC],[
|
||||
AC_MSG_CHECKING([if _Atomic is available])
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM([[
|
||||
$curl_includes_unistd
|
||||
]],[[
|
||||
_Atomic int i = 0;
|
||||
]])
|
||||
],[
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE_UNQUOTED(HAVE_ATOMIC, 1,
|
||||
[Define to 1 if you have _Atomic support.])
|
||||
tst_atomic="yes"
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
tst_atomic="no"
|
||||
])
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user