328 lines
8.8 KiB
Diff
328 lines
8.8 KiB
Diff
From 23af112f5556d6a785c17e09f2422ac931405f61 Mon Sep 17 00:00:00 2001
|
|
From: Thomas Guillem <thomas@gllm.fr>
|
|
Date: Tue, 5 Apr 2022 15:46:03 +0200
|
|
Subject: [PATCH 1/1] 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
|
|
|
|
Conflict:update easy_lock.h to latest
|
|
Reference:https://github.com/curl/curl/commit/23af112f5556d6a785c17e09f2422ac931405f61
|
|
---
|
|
configure.ac | 2 ++
|
|
lib/Makefile.inc | 1 +
|
|
lib/easy.c | 52 +++++++++++++++++++++++++++++----
|
|
lib/easy_lock.h | 105 ++++++++++++++++++++++++++++++++++++++++++++
|
|
m4/curl-functions.m4 | 23 +++++++++++++++
|
|
5 files changed, 178 insertions(+), 5 deletions(-)
|
|
create mode 100644 lib/easy_lock.h
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 3910ec631..009f32c32 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -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 \
|
|
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
|
|
index 1ab007896..f756515d6 100644
|
|
--- a/lib/Makefile.inc
|
|
+++ b/lib/Makefile.inc
|
|
@@ -262,6 +262,7 @@ LIB_HFILES = \
|
|
doh.h \
|
|
dotdot.h \
|
|
dynbuf.h \
|
|
+ easy_lock.h \
|
|
easyif.h \
|
|
easyoptions.h \
|
|
escape.h \
|
|
diff --git a/lib/easy.c b/lib/easy.c
|
|
index 336cada87..7781c8e16 100644
|
|
--- a/lib/easy.c
|
|
+++ b/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)
|
|
+ global_init_lock();
|
|
+
|
|
+ if(!initialized) {
|
|
+ global_init_unlock();
|
|
return;
|
|
+ }
|
|
|
|
- if(--initialized)
|
|
+ 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);
|
|
diff --git a/lib/easy_lock.h b/lib/easy_lock.h
|
|
new file mode 100644
|
|
index 000000000..41627c4d4
|
|
--- /dev/null
|
|
+++ b/lib/easy_lock.h
|
|
@@ -0,0 +1,105 @@
|
|
+/***************************************************************************
|
|
+ * _ _ ____ _
|
|
+ * Project ___| | | | _ \| |
|
|
+ * / __| | | | |_) | |
|
|
+ * | (__| |_| | _ <| |___
|
|
+ * \___|\___/|_| \_\_____|
|
|
+ *
|
|
+ * Copyright (C) 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.
|
|
+ *
|
|
+ * SPDX-License-Identifier: curl
|
|
+ *
|
|
+ ***************************************************************************/
|
|
+
|
|
+#include "curl_setup.h"
|
|
+
|
|
+#define GLOBAL_INIT_IS_THREADSAFE
|
|
+
|
|
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
|
|
+
|
|
+#ifdef __MINGW32__
|
|
+#ifndef __MINGW64_VERSION_MAJOR
|
|
+#if (__MINGW32_MAJOR_VERSION < 5) || \
|
|
+ (__MINGW32_MAJOR_VERSION == 5 && __MINGW32_MINOR_VERSION == 0)
|
|
+/* mingw >= 5.0.1 defines SRWLOCK, and slightly different from MS define */
|
|
+typedef PVOID SRWLOCK, *PSRWLOCK;
|
|
+#endif
|
|
+#endif
|
|
+#ifndef SRWLOCK_INIT
|
|
+#define SRWLOCK_INIT NULL
|
|
+#endif
|
|
+#endif /* __MINGW32__ */
|
|
+
|
|
+#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) && defined(HAVE_STDATOMIC_H)
|
|
+#include <stdatomic.h>
|
|
+#if defined(HAVE_SCHED_YIELD)
|
|
+#include <sched.h>
|
|
+#endif
|
|
+
|
|
+#define curl_simple_lock atomic_int
|
|
+#define CURL_SIMPLE_LOCK_INIT 0
|
|
+
|
|
+/* a clang-thing */
|
|
+#ifndef __has_builtin
|
|
+#define __has_builtin(x) 0
|
|
+#endif
|
|
+
|
|
+#ifndef __INTEL_COMPILER
|
|
+/* The Intel compiler tries to look like GCC *and* clang *and* lies in its
|
|
+ __has_builtin() function, so override it. */
|
|
+
|
|
+/* if GCC on i386/x86_64 or if the built-in is present */
|
|
+#if ( (defined(__GNUC__) && !defined(__clang__)) && \
|
|
+ (defined(__i386__) || defined(__x86_64__))) || \
|
|
+ __has_builtin(__builtin_ia32_pause)
|
|
+#define HAVE_BUILTIN_IA32_PAUSE
|
|
+#endif
|
|
+
|
|
+#endif
|
|
+
|
|
+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) */
|
|
+#ifdef HAVE_BUILTIN_IA32_PAUSE
|
|
+ __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
|
|
diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4
|
|
index b40d42798..eb85dce4a 100644
|
|
--- a/m4/curl-functions.m4
|
|
+++ b/m4/curl-functions.m4
|
|
@@ -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"
|
|
+ ])
|
|
+])
|
|
--
|
|
2.33.0
|
|
|