diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.inc | 1 | ||||
-rw-r--r-- | lib/easy.c | 52 | ||||
-rw-r--r-- | lib/easy_lock.h | 69 |
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 |