summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.inc1
-rw-r--r--lib/easy.c52
-rw-r--r--lib/easy_lock.h69
3 files changed, 117 insertions, 5 deletions
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,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