mirror of
https://github.com/curl/curl.git
synced 2026-04-14 18:21:40 +03:00
share: concurrency handling, easy updates
Replace the `volatile int dirty` with a reference counter protected by a mutex when available. Solve the problem of when to call application's lock function by adding a volatile flag that indicates a share has been added to easy handles in its lifetime. That flag ever goes from FALSE to TRUE, so volatile might work (in the absence of a mutex). (The problem is that the lock/unlock functions need 2-3 `curl_share_setopt()` invocations to become usable and there is no way of telling if the third will ever happen. Calling the lock function before the 3rd setopt may crash the application.) When removing a share from an easy handle (or replacing it with another share), detach the easy connection on a share with a connection pool. When cleaning up a share, allow this even if it is still used in easy handles. It will be destroyed when the reference count drops to 0. Closes #20870
This commit is contained in:
parent
745344ea4e
commit
82009c4220
26 changed files with 378 additions and 210 deletions
|
|
@ -630,15 +630,20 @@ if(DOS OR AMIGA)
|
||||||
set(HAVE_TIME_T_UNSIGNED 1)
|
set(HAVE_TIME_T_UNSIGNED 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
find_package(Threads)
|
||||||
|
set(HAVE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT})
|
||||||
|
set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT})
|
||||||
|
list(APPEND CURL_NETWORK_AND_TIME_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_THREADED_RESOLVER)
|
if(ENABLE_THREADED_RESOLVER)
|
||||||
if(WIN32)
|
if(NOT WIN32 AND NOT HAVE_THREADS_POSIX)
|
||||||
set(USE_THREADS_WIN32 ON)
|
message(FATAL_ERROR "Threaded resolver requires POSIX Threads.")
|
||||||
else()
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT})
|
|
||||||
set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT})
|
|
||||||
list(APPEND CURL_NETWORK_AND_TIME_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
|
||||||
endif()
|
endif()
|
||||||
|
set(USE_RESOLV_THREADED ON)
|
||||||
|
elseif(USE_ARES)
|
||||||
|
set(USE_RESOLV_ARES ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Check for all needed libraries
|
# Check for all needed libraries
|
||||||
|
|
@ -1998,8 +2003,8 @@ curl_add_if("libz" HAVE_LIBZ)
|
||||||
curl_add_if("brotli" HAVE_BROTLI)
|
curl_add_if("brotli" HAVE_BROTLI)
|
||||||
curl_add_if("gsasl" USE_GSASL)
|
curl_add_if("gsasl" USE_GSASL)
|
||||||
curl_add_if("zstd" HAVE_ZSTD)
|
curl_add_if("zstd" HAVE_ZSTD)
|
||||||
curl_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
|
curl_add_if("AsynchDNS" USE_RESOLV_ARES OR USE_RESOLV_THREADED)
|
||||||
curl_add_if("asyn-rr" USE_ARES AND ENABLE_THREADED_RESOLVER AND USE_HTTPSRR)
|
curl_add_if("asyn-rr" USE_ARES AND USE_RESOLV_THREADED AND USE_HTTPSRR)
|
||||||
curl_add_if("IDN" (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
|
curl_add_if("IDN" (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
|
||||||
USE_WIN32_IDN OR
|
USE_WIN32_IDN OR
|
||||||
USE_APPLE_IDN)
|
USE_APPLE_IDN)
|
||||||
|
|
@ -2022,7 +2027,7 @@ curl_add_if("HTTPS-proxy" NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPE
|
||||||
OR USE_SCHANNEL OR USE_RUSTLS OR USE_MBEDTLS OR
|
OR USE_SCHANNEL OR USE_RUSTLS OR USE_MBEDTLS OR
|
||||||
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO_NEW)))
|
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO_NEW)))
|
||||||
curl_add_if("Unicode" ENABLE_UNICODE)
|
curl_add_if("Unicode" ENABLE_UNICODE)
|
||||||
curl_add_if("threadsafe" HAVE_ATOMIC OR (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR WIN32)
|
curl_add_if("threadsafe" HAVE_ATOMIC OR (HAVE_THREADS_POSIX AND HAVE_PTHREAD_H) OR WIN32)
|
||||||
curl_add_if("Debug" ENABLE_DEBUG)
|
curl_add_if("Debug" ENABLE_DEBUG)
|
||||||
curl_add_if("ECH" _ssl_enabled AND HAVE_ECH)
|
curl_add_if("ECH" _ssl_enabled AND HAVE_ECH)
|
||||||
curl_add_if("HTTPSRR" _ssl_enabled AND USE_HTTPSRR)
|
curl_add_if("HTTPSRR" _ssl_enabled AND USE_HTTPSRR)
|
||||||
|
|
|
||||||
47
configure.ac
47
configure.ac
|
|
@ -4246,15 +4246,8 @@ if test "$ipv6" = "yes" && test "$curl_cv_apple" = "yes"; then
|
||||||
CURL_DARWIN_SYSTEMCONFIGURATION
|
CURL_DARWIN_SYSTEMCONFIGURATION
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Windows threaded resolver check
|
|
||||||
if test "$want_threaded_resolver" = "yes" && test "$curl_cv_native_windows" = "yes"; then
|
|
||||||
USE_THREADS_WIN32=1
|
|
||||||
AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup])
|
|
||||||
curl_res_msg="Win32 threaded"
|
|
||||||
fi
|
|
||||||
|
|
||||||
dnl detect pthreads
|
dnl detect pthreads
|
||||||
if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; then
|
if test "$curl_cv_native_windows" != "yes"; then
|
||||||
AC_CHECK_HEADER(pthread.h,
|
AC_CHECK_HEADER(pthread.h,
|
||||||
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
|
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
|
||||||
save_CFLAGS="$CFLAGS"
|
save_CFLAGS="$CFLAGS"
|
||||||
|
|
@ -4267,7 +4260,7 @@ if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; t
|
||||||
|
|
||||||
LIBS=
|
LIBS=
|
||||||
dnl Check for libc variants without a separate pthread lib like bionic
|
dnl Check for libc variants without a separate pthread lib like bionic
|
||||||
AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] )
|
AC_CHECK_FUNC(pthread_create, [HAVE_THREADS_POSIX=1] )
|
||||||
LIBS="$save_LIBS"
|
LIBS="$save_LIBS"
|
||||||
|
|
||||||
case $host in
|
case $host in
|
||||||
|
|
@ -4279,7 +4272,7 @@ if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; t
|
||||||
esac
|
esac
|
||||||
|
|
||||||
dnl if it was not found without lib, search for it in pthread lib
|
dnl if it was not found without lib, search for it in pthread lib
|
||||||
if test "$USE_THREADS_POSIX" != "1"; then
|
if test "$HAVE_THREADS_POSIX" != "1"; then
|
||||||
# assign PTHREAD for pkg-config use
|
# assign PTHREAD for pkg-config use
|
||||||
PTHREAD=" -pthread"
|
PTHREAD=" -pthread"
|
||||||
|
|
||||||
|
|
@ -4302,20 +4295,32 @@ if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; t
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
AC_CHECK_LIB(pthread, pthread_create,
|
AC_CHECK_LIB(pthread, pthread_create,
|
||||||
[USE_THREADS_POSIX=1],
|
[HAVE_THREADS_POSIX=1],
|
||||||
[ CFLAGS="$save_CFLAGS"])
|
[ CFLAGS="$save_CFLAGS"])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$USE_THREADS_POSIX" = "1"; then
|
|
||||||
AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup])
|
|
||||||
curl_res_msg="POSIX threaded"
|
|
||||||
fi
|
|
||||||
])
|
])
|
||||||
|
if test "$HAVE_THREADS_POSIX" = "1"; then
|
||||||
|
AC_DEFINE(HAVE_THREADS_POSIX, 1, [if POSIX pthreads are supported])
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Did we find a threading option?
|
dnl threaded resolver check
|
||||||
if test "$want_threaded_resolver" != "no" && test "$USE_THREADS_POSIX" != "1" && test "$USE_THREADS_WIN32" != "1"; then
|
if test "$want_threaded_resolver" = "yes"; then
|
||||||
AC_MSG_ERROR([Threaded resolver enabled but no thread library found])
|
if test "$curl_cv_native_windows" = "yes"; then
|
||||||
|
USE_RESOLV_THREADED=1
|
||||||
|
AC_DEFINE(USE_RESOLV_THREADED, 1, [if you want threaded DNS lookup])
|
||||||
|
curl_res_msg="Win32 threaded"
|
||||||
|
elif test "$HAVE_THREADS_POSIX" = "1"; then
|
||||||
|
USE_RESOLV_THREADED=1
|
||||||
|
AC_DEFINE(USE_RESOLV_THREADED, 1, [if you want threaded DNS lookup])
|
||||||
|
curl_res_msg="POSIX threaded"
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([Threaded resolver enabled but no thread library found])
|
||||||
|
fi
|
||||||
|
elif test "$USE_ARES" = "1"; then
|
||||||
|
USE_RESOLV_ARES=1
|
||||||
|
AC_DEFINE(USE_RESOLV_ARES, 1, [if you want c-ares for DNS lookup])
|
||||||
|
curl_res_msg="c-ares"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_HEADER(dirent.h,
|
AC_CHECK_HEADER(dirent.h,
|
||||||
|
|
@ -5157,7 +5162,7 @@ fi
|
||||||
if test "$HAVE_ZSTD" = "1"; then
|
if test "$HAVE_ZSTD" = "1"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES zstd"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES zstd"
|
||||||
fi
|
fi
|
||||||
if test "$USE_ARES" = "1" || test "$USE_THREADS_POSIX" = "1" || test "$USE_THREADS_WIN32" = "1"; then
|
if test "$USE_RESOLV_ARES" = "1" || test "$USE_RESOLV_THREADED" = "1"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
|
||||||
fi
|
fi
|
||||||
if test "$USE_ARES" = "1" && test "$want_threaded_resolver" = "yes" && test "$want_httpsrr" != "no"; then
|
if test "$USE_ARES" = "1" && test "$want_threaded_resolver" = "yes" && test "$want_httpsrr" != "no"; then
|
||||||
|
|
@ -5291,7 +5296,7 @@ fi
|
||||||
|
|
||||||
if test "$tst_atomic" = "yes"; then
|
if test "$tst_atomic" = "yes"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
||||||
elif test "$USE_THREADS_POSIX" = "1" && test "$ac_cv_header_pthread_h" = "yes"; then
|
elif test "$HAVE_THREADS_POSIX" = "1" && test "$ac_cv_header_pthread_h" = "yes"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
||||||
elif test "$curl_cv_native_windows" = "yes"; then
|
elif test "$curl_cv_native_windows" = "yes"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ CURLSHcode curl_share_cleanup(CURLSH *share_handle);
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
This function deletes a shared object. The share handle cannot be used anymore
|
This function deletes a shared object. The share handle cannot be used anymore
|
||||||
when this function has been called.
|
when this function has been called. The share fails the call if it is
|
||||||
|
still being used in any easy handle.
|
||||||
|
|
||||||
Passing in a NULL pointer in *share_handle* makes this function return
|
Passing in a NULL pointer in *share_handle* makes this function return
|
||||||
immediately with no action.
|
immediately with no action.
|
||||||
|
|
@ -35,6 +36,11 @@ immediately with no action.
|
||||||
Any use of the **share_handle** after this function has been called and have
|
Any use of the **share_handle** after this function has been called and have
|
||||||
returned, is illegal.
|
returned, is illegal.
|
||||||
|
|
||||||
|
For applications that use a share in several threads, it is critical that
|
||||||
|
the destruction of the share is only done when all other threads have stopped
|
||||||
|
using it. While libcurl tracks how many easy handles are using a share,
|
||||||
|
it can not observe how many pointers to the share the application has.
|
||||||
|
|
||||||
# %PROTOCOLS%
|
# %PROTOCOLS%
|
||||||
|
|
||||||
# EXAMPLE
|
# EXAMPLE
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, uint16_t port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef USE_RESOLV_THREADED
|
||||||
/* gethostbyname() is not thread-safe, so we need to reopen bsdsocket
|
/* gethostbyname() is not thread-safe, so we need to reopen bsdsocket
|
||||||
* on the thread's context
|
* on the thread's context
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Only for ares-enabled builds and only for functions that fulfill
|
* Only for ares-enabled builds and only for functions that fulfill
|
||||||
|
|
@ -966,4 +966,4 @@ CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CURLRES_ARES */
|
#endif /* USE_RESOLV_ARES */
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,10 @@ void Curl_async_shutdown(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
if(data->state.async) {
|
if(data->state.async) {
|
||||||
CURL_TRC_DNS(data, "shutdown async");
|
CURL_TRC_DNS(data, "shutdown async");
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
Curl_async_ares_shutdown(data, data->state.async);
|
Curl_async_ares_shutdown(data, data->state.async);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef USE_RESOLV_THREADED
|
||||||
Curl_async_thrdd_shutdown(data, data->state.async);
|
Curl_async_thrdd_shutdown(data, data->state.async);
|
||||||
#endif
|
#endif
|
||||||
#ifndef CURL_DISABLE_DOH
|
#ifndef CURL_DISABLE_DOH
|
||||||
|
|
@ -199,10 +199,10 @@ void Curl_async_destroy(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
if(data->state.async) {
|
if(data->state.async) {
|
||||||
CURL_TRC_DNS(data, "destroy async");
|
CURL_TRC_DNS(data, "destroy async");
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
Curl_async_ares_destroy(data, data->state.async);
|
Curl_async_ares_destroy(data, data->state.async);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef USE_RESOLV_THREADED
|
||||||
Curl_async_thrdd_destroy(data, data->state.async);
|
Curl_async_thrdd_destroy(data, data->state.async);
|
||||||
#endif
|
#endif
|
||||||
#ifndef CURL_DISABLE_DOH
|
#ifndef CURL_DISABLE_DOH
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Only for threaded name resolves builds
|
* Only for threaded name resolves builds
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef USE_RESOLV_THREADED
|
||||||
|
|
||||||
#include "socketpair.h"
|
#include "socketpair.h"
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
#include <inet.h>
|
#include <inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
#if defined(HAVE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -739,4 +739,4 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||||
|
|
||||||
#endif /* !HAVE_GETADDRINFO */
|
#endif /* !HAVE_GETADDRINFO */
|
||||||
|
|
||||||
#endif /* CURLRES_THREADED */
|
#endif /* USE_RESOLV_THREADED */
|
||||||
|
|
|
||||||
16
lib/asyn.h
16
lib/asyn.h
|
|
@ -41,8 +41,8 @@ struct hostent;
|
||||||
struct connectdata;
|
struct connectdata;
|
||||||
struct easy_pollset;
|
struct easy_pollset;
|
||||||
|
|
||||||
#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
|
#if defined(USE_RESOLV_ARES) && defined(USE_RESOLV_THREADED)
|
||||||
#error cannot have both CURLRES_ARES and CURLRES_THREADED defined
|
#error cannot have both USE_RESOLV_ARES and USE_RESOLV_THREADED defined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -134,7 +134,7 @@ CURLcode Curl_ares_pollset(struct Curl_easy *data,
|
||||||
int Curl_ares_perform(ares_channel channel, timediff_t timeout_ms);
|
int Curl_ares_perform(ares_channel channel, timediff_t timeout_ms);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
/* async resolving implementation using c-ares alone */
|
/* async resolving implementation using c-ares alone */
|
||||||
struct async_ares_ctx {
|
struct async_ares_ctx {
|
||||||
ares_channel channel;
|
ares_channel channel;
|
||||||
|
|
@ -168,9 +168,9 @@ CURLcode Curl_async_ares_set_dns_local_ip4(struct Curl_easy *data);
|
||||||
/* Set the local ipv6 address to use by ares, from `data` settings. */
|
/* Set the local ipv6 address to use by ares, from `data` settings. */
|
||||||
CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data);
|
CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data);
|
||||||
|
|
||||||
#endif /* CURLRES_ARES */
|
#endif /* USE_RESOLV_ARES */
|
||||||
|
|
||||||
#ifdef CURLRES_THREADED
|
#ifdef USE_RESOLV_THREADED
|
||||||
/* async resolving implementation using POSIX threads */
|
/* async resolving implementation using POSIX threads */
|
||||||
#include "curl_threads.h"
|
#include "curl_threads.h"
|
||||||
|
|
||||||
|
|
@ -219,7 +219,7 @@ void Curl_async_thrdd_shutdown(struct Curl_easy *data,
|
||||||
void Curl_async_thrdd_destroy(struct Curl_easy *data,
|
void Curl_async_thrdd_destroy(struct Curl_easy *data,
|
||||||
struct Curl_resolv_async *async);
|
struct Curl_resolv_async *async);
|
||||||
|
|
||||||
#endif /* CURLRES_THREADED */
|
#endif /* USE_RESOLV_THREADED */
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_DOH
|
#ifndef CURL_DISABLE_DOH
|
||||||
struct doh_probes;
|
struct doh_probes;
|
||||||
|
|
@ -242,9 +242,9 @@ struct doh_probes;
|
||||||
|
|
||||||
#ifdef USE_CURL_ASYNC
|
#ifdef USE_CURL_ASYNC
|
||||||
struct Curl_resolv_async {
|
struct Curl_resolv_async {
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
struct async_ares_ctx ares;
|
struct async_ares_ctx ares;
|
||||||
#elif defined(CURLRES_THREADED)
|
#elif defined(USE_RESOLV_THREADED)
|
||||||
struct async_thrdd_ctx thrdd;
|
struct async_thrdd_ctx thrdd;
|
||||||
#endif
|
#endif
|
||||||
#ifndef CURL_DISABLE_DOH
|
#ifndef CURL_DISABLE_DOH
|
||||||
|
|
|
||||||
|
|
@ -262,15 +262,16 @@
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS.
|
* Undefine both USE_ARES and USE_RESOLV_THREADED for synchronous DNS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Default define to enable threaded asynchronous DNS lookups. */
|
/* Default define to enable threaded asynchronous DNS lookups. */
|
||||||
#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && !defined(USE_THREADS_WIN32)
|
#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \
|
||||||
# define USE_THREADS_WIN32 1
|
!defined(USE_RESOLV_THREADED)
|
||||||
|
# define USE_RESOLV_THREADED 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_ARES) && defined(USE_THREADS_WIN32)
|
#if defined(USE_ARES) && defined(USE_RESOLV_THREADED)
|
||||||
# error "Only one DNS lookup specialty may be defined at most"
|
# error "Only one DNS lookup specialty may be defined at most"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,14 +643,17 @@ ${SIZEOF_TIME_T_CODE}
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
#cmakedefine STDC_HEADERS 1
|
#cmakedefine STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Define if you have POSIX pthreads */
|
||||||
|
#cmakedefine HAVE_THREADS_POSIX 1
|
||||||
|
|
||||||
/* Define if you want to enable c-ares support */
|
/* Define if you want to enable c-ares support */
|
||||||
#cmakedefine USE_ARES 1
|
#cmakedefine USE_ARES 1
|
||||||
|
|
||||||
/* Define if you want to enable POSIX threaded DNS lookup */
|
/* Define if you want to enable c-ares DNS lookup */
|
||||||
#cmakedefine USE_THREADS_POSIX 1
|
#cmakedefine USE_RESOLV_ARES 1
|
||||||
|
|
||||||
/* Define if you want to enable Win32 threaded DNS lookup */
|
/* Define if you want to enable threaded DNS lookup */
|
||||||
#cmakedefine USE_THREADS_WIN32 1
|
#cmakedefine USE_RESOLV_THREADED 1
|
||||||
|
|
||||||
/* if GnuTLS is enabled */
|
/* if GnuTLS is enabled */
|
||||||
#cmakedefine USE_GNUTLS 1
|
#cmakedefine USE_GNUTLS 1
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
|
|
||||||
/* Give calloc a chance to be dragging in early, so we do not redefine */
|
/* Give calloc a chance to be dragging in early, so we do not redefine */
|
||||||
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
#if defined(HAVE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -442,7 +442,7 @@
|
||||||
# if !(defined(__NEWLIB__) || \
|
# if !(defined(__NEWLIB__) || \
|
||||||
(defined(__CLIB2__) && defined(__THREAD_SAFE)))
|
(defined(__CLIB2__) && defined(__THREAD_SAFE)))
|
||||||
/* disable threaded resolver with clib2 - requires newlib or clib-ts */
|
/* disable threaded resolver with clib2 - requires newlib or clib-ts */
|
||||||
# undef USE_THREADS_POSIX
|
# undef USE_RESOLV_THREADED
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# include <exec/types.h>
|
# include <exec/types.h>
|
||||||
|
|
@ -685,6 +685,16 @@
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/* We want to use mutex when available. */
|
||||||
|
#if defined(HAVE_THREADS_POSIX) || defined(_WIN32)
|
||||||
|
#define USE_MUTEX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* threaded resolver is the only feature requiring threads. */
|
||||||
|
#ifdef USE_RESOLV_THREADED
|
||||||
|
#define USE_THREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
/* resolver specialty compile-time defines */
|
/* resolver specialty compile-time defines */
|
||||||
/* CURLRES_* defines to use in the host*.c sources */
|
/* CURLRES_* defines to use in the host*.c sources */
|
||||||
|
|
@ -702,12 +712,10 @@
|
||||||
# define CURLRES_IPV4
|
# define CURLRES_IPV4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_RESOLV_THREADED
|
||||||
# define CURLRES_ASYNCH
|
# define CURLRES_ASYNCH
|
||||||
# define CURLRES_THREADED
|
#elif defined(USE_RESOLV_ARES)
|
||||||
#elif defined(USE_ARES)
|
|
||||||
# define CURLRES_ASYNCH
|
# define CURLRES_ASYNCH
|
||||||
# define CURLRES_ARES
|
|
||||||
/* now undef the stock libc functions to avoid them being used */
|
/* now undef the stock libc functions to avoid them being used */
|
||||||
# undef HAVE_GETADDRINFO
|
# undef HAVE_GETADDRINFO
|
||||||
# undef HAVE_FREEADDRINFO
|
# undef HAVE_FREEADDRINFO
|
||||||
|
|
|
||||||
256
lib/curl_share.c
256
lib/curl_share.c
|
|
@ -24,22 +24,61 @@
|
||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
|
#include "multiif.h"
|
||||||
|
#include "curl_threads.h"
|
||||||
#include "curl_share.h"
|
#include "curl_share.h"
|
||||||
#include "vtls/vtls.h"
|
#include "vtls/vtls.h"
|
||||||
#include "vtls/vtls_scache.h"
|
#include "vtls/vtls_scache.h"
|
||||||
#include "hsts.h"
|
#include "hsts.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
|
|
||||||
|
static void share_destroy(struct Curl_share *share)
|
||||||
|
{
|
||||||
|
if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
|
||||||
|
Curl_cpool_destroy(&share->cpool);
|
||||||
|
}
|
||||||
|
|
||||||
|
Curl_dnscache_destroy(&share->dnscache);
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
|
Curl_cookie_cleanup(share->cookies);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_HSTS
|
||||||
|
Curl_hsts_cleanup(&share->hsts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SSL
|
||||||
|
if(share->ssl_scache) {
|
||||||
|
Curl_ssl_scache_destroy(share->ssl_scache);
|
||||||
|
share->ssl_scache = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Curl_psl_destroy(&share->psl);
|
||||||
|
Curl_close(&share->admin);
|
||||||
|
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_destroy(&share->lock);
|
||||||
|
#endif
|
||||||
|
share->magic = 0;
|
||||||
|
curlx_free(share);
|
||||||
|
}
|
||||||
|
|
||||||
CURLSH *curl_share_init(void)
|
CURLSH *curl_share_init(void)
|
||||||
{
|
{
|
||||||
struct Curl_share *share = curlx_calloc(1, sizeof(struct Curl_share));
|
struct Curl_share *share = curlx_calloc(1, sizeof(struct Curl_share));
|
||||||
if(share) {
|
if(share) {
|
||||||
share->magic = CURL_GOOD_SHARE;
|
share->magic = CURL_GOOD_SHARE;
|
||||||
share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
|
share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_init(&share->lock);
|
||||||
|
#endif
|
||||||
|
share->ref_count = 1;
|
||||||
Curl_dnscache_init(&share->dnscache, 23);
|
Curl_dnscache_init(&share->dnscache, 23);
|
||||||
share->admin = curl_easy_init();
|
share->admin = curl_easy_init();
|
||||||
if(!share->admin) {
|
if(!share->admin) {
|
||||||
curlx_free(share);
|
share_destroy(share);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* admin handles have mid 0 */
|
/* admin handles have mid 0 */
|
||||||
|
|
@ -50,10 +89,104 @@ CURLSH *curl_share_init(void)
|
||||||
share->admin->set.verbose = TRUE;
|
share->admin->set.verbose = TRUE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return share;
|
return share;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t share_ref_inc(struct Curl_share *share)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_acquire(&share->lock);
|
||||||
|
n = ++(share->ref_count);
|
||||||
|
share->has_been_shared = TRUE;
|
||||||
|
Curl_mutex_release(&share->lock);
|
||||||
|
#else
|
||||||
|
n = ++(share->ref_count);
|
||||||
|
share->has_been_shared = TRUE;
|
||||||
|
#endif
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t share_ref_dec(struct Curl_share *share)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_acquire(&share->lock);
|
||||||
|
DEBUGASSERT(share->ref_count);
|
||||||
|
n = --(share->ref_count);
|
||||||
|
Curl_mutex_release(&share->lock);
|
||||||
|
#else
|
||||||
|
n = --(share->ref_count);
|
||||||
|
#endif
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool share_has_been_shared(struct Curl_share *share)
|
||||||
|
{
|
||||||
|
bool was_shared;
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_acquire(&share->lock);
|
||||||
|
was_shared = share->has_been_shared;
|
||||||
|
Curl_mutex_release(&share->lock);
|
||||||
|
#else
|
||||||
|
was_shared = share->has_been_shared;
|
||||||
|
#endif
|
||||||
|
return was_shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool share_lock_acquire(struct Curl_share *share,
|
||||||
|
struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
if(share->lockfunc && share->unlockfunc &&
|
||||||
|
(data || share_has_been_shared(share))) {
|
||||||
|
share->lockfunc(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
|
||||||
|
share->clientdata);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void share_lock_release(struct Curl_share *share,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
bool locked)
|
||||||
|
{
|
||||||
|
if(locked) {
|
||||||
|
DEBUGASSERT(share->unlockfunc);
|
||||||
|
if(share->unlockfunc)
|
||||||
|
share->unlockfunc(data, CURL_LOCK_DATA_SHARE, share->clientdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool share_in_use(struct Curl_share *share)
|
||||||
|
{
|
||||||
|
bool in_use;
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
Curl_mutex_acquire(&share->lock);
|
||||||
|
in_use = (share->ref_count > 1);
|
||||||
|
Curl_mutex_release(&share->lock);
|
||||||
|
#else
|
||||||
|
bool locked = share_lock_acquire(share, NULL);
|
||||||
|
in_use = (share->ref_count > 1);
|
||||||
|
share_lock_release(share, NULL, locked);
|
||||||
|
#endif
|
||||||
|
return in_use;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void share_unlink(struct Curl_share **pshare,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
bool locked)
|
||||||
|
{
|
||||||
|
struct Curl_share *share = *pshare;
|
||||||
|
uint32_t n;
|
||||||
|
|
||||||
|
*pshare = NULL;
|
||||||
|
n = share_ref_dec(share);
|
||||||
|
if(locked)
|
||||||
|
share_lock_release(share, data, locked);
|
||||||
|
if(!n) /* last reference gone */
|
||||||
|
share_destroy(share);
|
||||||
|
}
|
||||||
|
|
||||||
#undef curl_share_setopt
|
#undef curl_share_setopt
|
||||||
CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
|
CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
|
||||||
{
|
{
|
||||||
|
|
@ -68,10 +201,11 @@ CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
|
||||||
if(!GOOD_SHARE_HANDLE(share))
|
if(!GOOD_SHARE_HANDLE(share))
|
||||||
return CURLSHE_INVALID;
|
return CURLSHE_INVALID;
|
||||||
|
|
||||||
if(share->dirty)
|
if(share_in_use(share)) {
|
||||||
/* do not allow setting options while one or more handles are already
|
/* do not allow setting options while one or more handles are already
|
||||||
using this share */
|
using this share */
|
||||||
return CURLSHE_IN_USE;
|
return CURLSHE_IN_USE;
|
||||||
|
}
|
||||||
|
|
||||||
va_start(param, option);
|
va_start(param, option);
|
||||||
|
|
||||||
|
|
@ -221,48 +355,15 @@ CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
|
||||||
CURLSHcode curl_share_cleanup(CURLSH *sh)
|
CURLSHcode curl_share_cleanup(CURLSH *sh)
|
||||||
{
|
{
|
||||||
struct Curl_share *share = sh;
|
struct Curl_share *share = sh;
|
||||||
|
bool locked;
|
||||||
if(!GOOD_SHARE_HANDLE(share))
|
if(!GOOD_SHARE_HANDLE(share))
|
||||||
return CURLSHE_INVALID;
|
return CURLSHE_INVALID;
|
||||||
|
|
||||||
if(share->lockfunc)
|
if(share_in_use(share))
|
||||||
share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
|
|
||||||
share->clientdata);
|
|
||||||
|
|
||||||
if(share->dirty) {
|
|
||||||
if(share->unlockfunc)
|
|
||||||
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
|
|
||||||
return CURLSHE_IN_USE;
|
return CURLSHE_IN_USE;
|
||||||
}
|
|
||||||
|
|
||||||
if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
|
|
||||||
Curl_cpool_destroy(&share->cpool);
|
|
||||||
}
|
|
||||||
|
|
||||||
Curl_dnscache_destroy(&share->dnscache);
|
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
|
||||||
Curl_cookie_cleanup(share->cookies);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_HSTS
|
|
||||||
Curl_hsts_cleanup(&share->hsts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_SSL
|
|
||||||
if(share->ssl_scache) {
|
|
||||||
Curl_ssl_scache_destroy(share->ssl_scache);
|
|
||||||
share->ssl_scache = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Curl_psl_destroy(&share->psl);
|
|
||||||
Curl_close(&share->admin);
|
|
||||||
|
|
||||||
if(share->unlockfunc)
|
|
||||||
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
|
|
||||||
share->magic = 0;
|
|
||||||
curlx_free(share);
|
|
||||||
|
|
||||||
|
locked = share_lock_acquire(share, NULL);
|
||||||
|
share_unlink(&share, NULL, locked);
|
||||||
return CURLSHE_OK;
|
return CURLSHE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,3 +398,78 @@ CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
|
||||||
|
|
||||||
return CURLSHE_OK;
|
return CURLSHE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_share_easy_unlink(struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
struct Curl_share *share = data->share;
|
||||||
|
|
||||||
|
if(share) {
|
||||||
|
bool locked = share_lock_acquire(share, data);
|
||||||
|
|
||||||
|
/* If data has a connection from this share, detach it. */
|
||||||
|
if(data->conn && (share->specifier & (1 << CURL_LOCK_DATA_CONNECT)))
|
||||||
|
Curl_detach_connection(data);
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
|
if(share->cookies == data->cookies)
|
||||||
|
data->cookies = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_HSTS
|
||||||
|
if(share->hsts == data->hsts)
|
||||||
|
data->hsts = NULL;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIBPSL
|
||||||
|
if(&share->psl == data->psl)
|
||||||
|
data->psl = data->multi ? &data->multi->psl : NULL;
|
||||||
|
#endif
|
||||||
|
if(share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
|
||||||
|
Curl_dns_entry_unlink(data, &data->state.dns[0]);
|
||||||
|
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
share_unlink(&data->share, data, locked);
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_share_easy_link(struct Curl_easy *data,
|
||||||
|
struct Curl_share *share)
|
||||||
|
{
|
||||||
|
if(data->share) {
|
||||||
|
DEBUGASSERT(0);
|
||||||
|
return CURLE_FAILED_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(share) {
|
||||||
|
bool locked = share_lock_acquire(share, data);
|
||||||
|
|
||||||
|
share_ref_inc(share);
|
||||||
|
data->share = share;
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
|
if(share->cookies) {
|
||||||
|
/* use shared cookie list, first free own one if any */
|
||||||
|
Curl_cookie_cleanup(data->cookies);
|
||||||
|
/* enable cookies since we now use a share that uses cookies! */
|
||||||
|
data->cookies = share->cookies;
|
||||||
|
}
|
||||||
|
#endif /* CURL_DISABLE_HTTP */
|
||||||
|
#ifndef CURL_DISABLE_HSTS
|
||||||
|
if(share->hsts) {
|
||||||
|
/* first free the private one if any */
|
||||||
|
Curl_hsts_cleanup(&data->hsts);
|
||||||
|
data->hsts = share->hsts;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIBPSL
|
||||||
|
if(share->specifier & (1 << CURL_LOCK_DATA_PSL))
|
||||||
|
data->psl = &share->psl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check for host cache not needed,
|
||||||
|
* it will be done by curl_easy_perform */
|
||||||
|
share_lock_release(share, data, locked);
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
|
#include "curl_threads.h"
|
||||||
#include "cookie.h"
|
#include "cookie.h"
|
||||||
#include "psl.h"
|
#include "psl.h"
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
|
|
@ -43,12 +44,22 @@ struct Curl_ssl_scache;
|
||||||
struct Curl_share {
|
struct Curl_share {
|
||||||
unsigned int magic; /* CURL_GOOD_SHARE */
|
unsigned int magic; /* CURL_GOOD_SHARE */
|
||||||
unsigned int specifier;
|
unsigned int specifier;
|
||||||
volatile unsigned int dirty;
|
|
||||||
|
|
||||||
|
uint32_t ref_count;
|
||||||
|
#ifdef USE_MUTEX
|
||||||
|
/* do `ref_count` and `has_been_shared` checks using this mutex. */
|
||||||
|
curl_mutex_t lock;
|
||||||
|
int has_been_shared;
|
||||||
|
#else
|
||||||
|
/* this only ever goes from FALSE -> TRUE once. We need to check
|
||||||
|
* this without being able to use the `lockfunc`. */
|
||||||
|
volatile int has_been_shared;
|
||||||
|
#endif
|
||||||
curl_lock_function lockfunc;
|
curl_lock_function lockfunc;
|
||||||
curl_unlock_function unlockfunc;
|
curl_unlock_function unlockfunc;
|
||||||
void *clientdata;
|
void *clientdata;
|
||||||
struct Curl_easy *admin;
|
struct Curl_easy *admin;
|
||||||
|
|
||||||
struct cpool cpool;
|
struct cpool cpool;
|
||||||
struct Curl_dnscache dnscache; /* DNS cache */
|
struct Curl_dnscache dnscache; /* DNS cache */
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
|
|
@ -74,4 +85,8 @@ CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type);
|
||||||
((data)->share->specifier & \
|
((data)->share->specifier & \
|
||||||
(1 << CURL_LOCK_DATA_SSL_SESSION)))
|
(1 << CURL_LOCK_DATA_SSL_SESSION)))
|
||||||
|
|
||||||
|
CURLcode Curl_share_easy_unlink(struct Curl_easy *data);
|
||||||
|
CURLcode Curl_share_easy_link(struct Curl_easy *data,
|
||||||
|
struct Curl_share *share);
|
||||||
|
|
||||||
#endif /* HEADER_CURL_SHARE_H */
|
#endif /* HEADER_CURL_SHARE_H */
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,11 @@
|
||||||
*
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "curl_threads.h"
|
#include "curl_threads.h"
|
||||||
|
|
||||||
#ifdef USE_THREADS_POSIX
|
#ifdef USE_THREADS
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS_POSIX
|
||||||
|
|
||||||
struct Curl_actual_call {
|
struct Curl_actual_call {
|
||||||
unsigned int (*func)(void *);
|
unsigned int (*func)(void *);
|
||||||
|
|
@ -97,7 +94,7 @@ int Curl_thread_join(curl_thread_t *hnd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(USE_THREADS_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
||||||
(CURL_STDCALL *func) (void *), void *arg)
|
(CURL_STDCALL *func) (void *), void *arg)
|
||||||
|
|
@ -131,4 +128,7 @@ int Curl_thread_join(curl_thread_t *hnd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_THREADS_* */
|
#else
|
||||||
|
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
|
||||||
|
#endif
|
||||||
|
#endif /* USE_THREADS */
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,11 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
|
|
||||||
#ifdef USE_THREADS_POSIX
|
#ifdef USE_MUTEX
|
||||||
|
#ifdef HAVE_THREADS_POSIX
|
||||||
|
#ifdef HAVE_PTHREAD_H
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
# define CURL_THREAD_RETURN_T unsigned int
|
# define CURL_THREAD_RETURN_T unsigned int
|
||||||
# define CURL_STDCALL
|
# define CURL_STDCALL
|
||||||
# define curl_mutex_t pthread_mutex_t
|
# define curl_mutex_t pthread_mutex_t
|
||||||
|
|
@ -35,7 +39,7 @@
|
||||||
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
|
# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
|
||||||
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
|
# define Curl_mutex_release(m) pthread_mutex_unlock(m)
|
||||||
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
|
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
|
||||||
#elif defined(USE_THREADS_WIN32)
|
#elif defined(_WIN32)
|
||||||
# define CURL_THREAD_RETURN_T DWORD
|
# define CURL_THREAD_RETURN_T DWORD
|
||||||
# define CURL_STDCALL WINAPI
|
# define CURL_STDCALL WINAPI
|
||||||
# define curl_mutex_t CRITICAL_SECTION
|
# define curl_mutex_t CRITICAL_SECTION
|
||||||
|
|
@ -45,9 +49,12 @@
|
||||||
# define Curl_mutex_acquire(m) EnterCriticalSection(m)
|
# define Curl_mutex_acquire(m) EnterCriticalSection(m)
|
||||||
# define Curl_mutex_release(m) LeaveCriticalSection(m)
|
# define Curl_mutex_release(m) LeaveCriticalSection(m)
|
||||||
# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
|
# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
|
||||||
|
#else
|
||||||
|
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* USE_MUTEX */
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_THREADS
|
||||||
|
|
||||||
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
|
||||||
(CURL_STDCALL *func) (void *), void *arg);
|
(CURL_STDCALL *func) (void *), void *arg);
|
||||||
|
|
@ -56,6 +63,6 @@ void Curl_thread_destroy(curl_thread_t *hnd);
|
||||||
|
|
||||||
int Curl_thread_join(curl_thread_t *hnd);
|
int Curl_thread_join(curl_thread_t *hnd);
|
||||||
|
|
||||||
#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
|
#endif /* USE_THREADS */
|
||||||
|
|
||||||
#endif /* HEADER_CURL_THREADS_H */
|
#endif /* HEADER_CURL_THREADS_H */
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ static CURL_INLINE void curl_simple_lock_unlock(curl_simple_lock *lock)
|
||||||
atomic_store_explicit(lock, false, memory_order_release);
|
atomic_store_explicit(lock, false, memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
#elif defined(HAVE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,10 @@
|
||||||
* take that into account. Hosts that are not IPv6-enabled have CURLRES_IPV4
|
* take that into account. Hosts that are not IPv6-enabled have CURLRES_IPV4
|
||||||
* defined.
|
* defined.
|
||||||
*
|
*
|
||||||
* CURLRES_ARES - is defined if libcurl is built to use c-ares for
|
* USE_RESOLV_ARES - is defined if libcurl is built to use c-ares for
|
||||||
* asynchronous name resolves. This can be Windows or *nix.
|
* asynchronous name resolves. This can be Windows or *nix.
|
||||||
*
|
*
|
||||||
* CURLRES_THREADED - is defined if libcurl is built to run under (native)
|
* USE_RESOLV_THREADED - is defined if libcurl is built to run under (native)
|
||||||
* Windows, and then the name resolve will be done in a new thread, and the
|
* Windows, and then the name resolve will be done in a new thread, and the
|
||||||
* supported API will be the same as for ares-builds.
|
* supported API will be the same as for ares-builds.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
|
||||||
#endif /* CURLRES_SYNCH */
|
#endif /* CURLRES_SYNCH */
|
||||||
#endif /* CURLRES_IPV4 */
|
#endif /* CURLRES_IPV4 */
|
||||||
|
|
||||||
#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA)
|
#if defined(CURLRES_IPV4) && !defined(USE_RESOLV_ARES) && \
|
||||||
|
!defined(CURLRES_AMIGA)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_ipv4_resolve_r() - ipv4 thread-safe resolver function.
|
* Curl_ipv4_resolve_r() - ipv4 thread-safe resolver function.
|
||||||
|
|
@ -277,4 +278,4 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
||||||
|
|
||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
#endif /* CURLRES_IPV4 && !CURLRES_ARES && !CURLRES_AMIGA */
|
#endif /* CURLRES_IPV4 && !USE_RESOLV_ARES && !CURLRES_AMIGA */
|
||||||
|
|
|
||||||
|
|
@ -65,14 +65,14 @@ static struct backtrace_state *btstate;
|
||||||
static char membuf[10000];
|
static char membuf[10000];
|
||||||
static size_t memwidx = 0; /* write index */
|
static size_t memwidx = 0; /* write index */
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_MUTEX
|
||||||
static bool dbg_mutex_init = 0;
|
static bool dbg_mutex_init = 0;
|
||||||
static curl_mutex_t dbg_mutex;
|
static curl_mutex_t dbg_mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool curl_dbg_lock(void)
|
static bool curl_dbg_lock(void)
|
||||||
{
|
{
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_MUTEX
|
||||||
if(dbg_mutex_init) {
|
if(dbg_mutex_init) {
|
||||||
Curl_mutex_acquire(&dbg_mutex);
|
Curl_mutex_acquire(&dbg_mutex);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
@ -83,7 +83,7 @@ static bool curl_dbg_lock(void)
|
||||||
|
|
||||||
static void curl_dbg_unlock(bool was_locked)
|
static void curl_dbg_unlock(bool was_locked)
|
||||||
{
|
{
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_MUTEX
|
||||||
if(was_locked)
|
if(was_locked)
|
||||||
Curl_mutex_release(&dbg_mutex);
|
Curl_mutex_release(&dbg_mutex);
|
||||||
#else
|
#else
|
||||||
|
|
@ -108,7 +108,7 @@ static void curl_dbg_cleanup(void)
|
||||||
fclose(curl_dbg_logfile);
|
fclose(curl_dbg_logfile);
|
||||||
}
|
}
|
||||||
curl_dbg_logfile = NULL;
|
curl_dbg_logfile = NULL;
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_MUTEX
|
||||||
if(dbg_mutex_init) {
|
if(dbg_mutex_init) {
|
||||||
Curl_mutex_destroy(&dbg_mutex);
|
Curl_mutex_destroy(&dbg_mutex);
|
||||||
dbg_mutex_init = FALSE;
|
dbg_mutex_init = FALSE;
|
||||||
|
|
@ -157,7 +157,7 @@ void curl_dbg_memdebug(const char *logname)
|
||||||
setbuf(curl_dbg_logfile, (char *)NULL);
|
setbuf(curl_dbg_logfile, (char *)NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_MUTEX
|
||||||
if(!dbg_mutex_init) {
|
if(!dbg_mutex_init) {
|
||||||
dbg_mutex_init = TRUE;
|
dbg_mutex_init = TRUE;
|
||||||
Curl_mutex_init(&dbg_mutex);
|
Curl_mutex_init(&dbg_mutex);
|
||||||
|
|
|
||||||
70
lib/setopt.c
70
lib/setopt.c
|
|
@ -1490,67 +1490,17 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option,
|
||||||
case CURLOPT_SHARE: {
|
case CURLOPT_SHARE: {
|
||||||
struct Curl_share *set = va_arg(param, struct Curl_share *);
|
struct Curl_share *set = va_arg(param, struct Curl_share *);
|
||||||
|
|
||||||
/* disconnect from old share, if any */
|
/* disconnect from old share, if any and possible */
|
||||||
if(data->share) {
|
result = Curl_share_easy_unlink(data);
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
/* use new share if it set */
|
||||||
if(data->share->cookies == data->cookies)
|
if(GOOD_SHARE_HANDLE(set)) {
|
||||||
data->cookies = NULL;
|
result = Curl_share_easy_link(data, set);
|
||||||
#endif
|
if(result)
|
||||||
|
return result;
|
||||||
#ifndef CURL_DISABLE_HSTS
|
|
||||||
if(data->share->hsts == data->hsts)
|
|
||||||
data->hsts = NULL;
|
|
||||||
#endif
|
|
||||||
#ifdef USE_LIBPSL
|
|
||||||
if(data->psl == &data->share->psl)
|
|
||||||
data->psl = data->multi ? &data->multi->psl : NULL;
|
|
||||||
#endif
|
|
||||||
if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
|
|
||||||
Curl_dns_entry_unlink(data, &data->state.dns[0]);
|
|
||||||
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->share->dirty--;
|
|
||||||
|
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
|
|
||||||
data->share = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GOOD_SHARE_HANDLE(set))
|
|
||||||
/* use new share if it set */
|
|
||||||
data->share = set;
|
|
||||||
if(data->share) {
|
|
||||||
|
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
|
|
||||||
|
|
||||||
data->share->dirty++;
|
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
|
||||||
if(data->share->cookies) {
|
|
||||||
/* use shared cookie list, first free own one if any */
|
|
||||||
Curl_cookie_cleanup(data->cookies);
|
|
||||||
/* enable cookies since we now use a share that uses cookies! */
|
|
||||||
data->cookies = data->share->cookies;
|
|
||||||
}
|
|
||||||
#endif /* CURL_DISABLE_HTTP */
|
|
||||||
#ifndef CURL_DISABLE_HSTS
|
|
||||||
if(data->share->hsts) {
|
|
||||||
/* first free the private one if any */
|
|
||||||
Curl_hsts_cleanup(&data->hsts);
|
|
||||||
data->hsts = data->share->hsts;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef USE_LIBPSL
|
|
||||||
if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
|
|
||||||
data->psl = &data->share->psl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
|
|
||||||
}
|
|
||||||
/* check for host cache not needed,
|
|
||||||
* it will be done by curl_easy_perform */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2434,7 +2384,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef CURLRES_ARES
|
#ifdef USE_RESOLV_ARES
|
||||||
case CURLOPT_DNS_SERVERS:
|
case CURLOPT_DNS_SERVERS:
|
||||||
result = Curl_setstropt(&s->str[STRING_DNS_SERVERS], ptr);
|
result = Curl_setstropt(&s->str[STRING_DNS_SERVERS], ptr);
|
||||||
if(result)
|
if(result)
|
||||||
|
|
|
||||||
|
|
@ -287,11 +287,8 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
||||||
data_priority_cleanup(data);
|
data_priority_cleanup(data);
|
||||||
|
|
||||||
/* No longer a dirty share, if it exists */
|
/* No longer a dirty share, if it exists */
|
||||||
if(data->share) {
|
if(Curl_share_easy_unlink(data))
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
|
DEBUGASSERT(0);
|
||||||
data->share->dirty--;
|
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Curl_hash_destroy(&data->meta_hash);
|
Curl_hash_destroy(&data->meta_hash);
|
||||||
#ifndef CURL_DISABLE_PROXY
|
#ifndef CURL_DISABLE_PROXY
|
||||||
|
|
|
||||||
|
|
@ -451,7 +451,7 @@ static const struct feat features_table[] = {
|
||||||
#ifndef CURL_DISABLE_ALTSVC
|
#ifndef CURL_DISABLE_ALTSVC
|
||||||
FEATURE("alt-svc", NULL, CURL_VERSION_ALTSVC),
|
FEATURE("alt-svc", NULL, CURL_VERSION_ALTSVC),
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_ARES) && defined(CURLRES_THREADED) && defined(USE_HTTPSRR)
|
#if defined(USE_ARES) && defined(USE_RESOLV_THREADED) && defined(USE_HTTPSRR)
|
||||||
FEATURE("asyn-rr", NULL, 0),
|
FEATURE("asyn-rr", NULL, 0),
|
||||||
#endif
|
#endif
|
||||||
#ifdef CURLRES_ASYNCH
|
#ifdef CURLRES_ASYNCH
|
||||||
|
|
|
||||||
|
|
@ -327,8 +327,8 @@ $write cvh "#endif"
|
||||||
$write cvh "#ifdef USE_OPENLDAP"
|
$write cvh "#ifdef USE_OPENLDAP"
|
||||||
$write cvh "#undef USE_OPENLDAP"
|
$write cvh "#undef USE_OPENLDAP"
|
||||||
$write cvh "#endif"
|
$write cvh "#endif"
|
||||||
$write cvh "#ifdef USE_THREADS_POSIX"
|
$write cvh "#ifdef USE_RESOLV_THREADED"
|
||||||
$write cvh "#undef USE_THREADS_POSIX"
|
$write cvh "#undef USE_RESOLV_THREADED"
|
||||||
$write cvh "#endif"
|
$write cvh "#endif"
|
||||||
$write cvh "#ifdef USE_TLS_SRP"
|
$write cvh "#ifdef USE_TLS_SRP"
|
||||||
$write cvh "#undef USE_TLS_SRP"
|
$write cvh "#undef USE_TLS_SRP"
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include "multihandle.h" /* for ENABLE_WAKEUP */
|
#include "multihandle.h" /* for ENABLE_WAKEUP */
|
||||||
#include "tool_xattr.h" /* for USE_XATTR */
|
#include "tool_xattr.h" /* for USE_XATTR */
|
||||||
#include "curl_sha512_256.h" /* for CURL_HAVE_SHA512_256 */
|
#include "curl_sha512_256.h" /* for CURL_HAVE_SHA512_256 */
|
||||||
#include "asyn.h" /* for CURLRES_ARES */
|
#include "asyn.h" /* for USE_RESOLV_ARES */
|
||||||
#include "fake_addrinfo.h" /* for USE_FAKE_GETADDRINFO */
|
#include "fake_addrinfo.h" /* for USE_FAKE_GETADDRINFO */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -235,7 +235,7 @@ static const char *disabled[] = {
|
||||||
,
|
,
|
||||||
"override-dns: "
|
"override-dns: "
|
||||||
#if defined(CURL_MEMDEBUG) && \
|
#if defined(CURL_MEMDEBUG) && \
|
||||||
(defined(CURLRES_ARES) || defined(USE_FAKE_GETADDRINFO))
|
(defined(USE_RESOLV_ARES) || defined(USE_FAKE_GETADDRINFO))
|
||||||
"ON"
|
"ON"
|
||||||
#else
|
#else
|
||||||
"OFF"
|
"OFF"
|
||||||
|
|
|
||||||
|
|
@ -227,17 +227,15 @@ loaded cookies:
|
||||||
.host.foo.com TRUE / FALSE %days[400] injected yes
|
.host.foo.com TRUE / FALSE %days[400] injected yes
|
||||||
-----------------
|
-----------------
|
||||||
try SHARE_CLEANUP...
|
try SHARE_CLEANUP...
|
||||||
lock: share [Pigs in space]: 98
|
|
||||||
unlock: share [Pigs in space]: 99
|
|
||||||
SHARE_CLEANUP failed, correct
|
SHARE_CLEANUP failed, correct
|
||||||
CLEANUP
|
CLEANUP
|
||||||
lock: cookie [Pigs in space]: 100
|
lock: cookie [Pigs in space]: 98
|
||||||
unlock: cookie [Pigs in space]: 101
|
unlock: cookie [Pigs in space]: 99
|
||||||
|
lock: share [Pigs in space]: 100
|
||||||
|
unlock: share [Pigs in space]: 101
|
||||||
|
SHARE_CLEANUP
|
||||||
lock: share [Pigs in space]: 102
|
lock: share [Pigs in space]: 102
|
||||||
unlock: share [Pigs in space]: 103
|
unlock: share [Pigs in space]: 103
|
||||||
SHARE_CLEANUP
|
|
||||||
lock: share [Pigs in space]: 104
|
|
||||||
unlock: share [Pigs in space]: 105
|
|
||||||
GLOBAL_CLEANUP
|
GLOBAL_CLEANUP
|
||||||
</stdout>
|
</stdout>
|
||||||
<file name="%LOGDIR/jar%TESTNUMBER" mode="text">
|
<file name="%LOGDIR/jar%TESTNUMBER" mode="text">
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "first.h"
|
#include "first.h"
|
||||||
|
|
||||||
#ifdef USE_THREADS_POSIX
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "curl_threads.h"
|
#include "curl_threads.h"
|
||||||
|
|
||||||
#define THREAD_SIZE 16
|
#define THREAD_SIZE 16
|
||||||
|
|
@ -66,7 +62,7 @@ static size_t write_memory_callback(char *contents, size_t size,
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_THREADS
|
||||||
static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr)
|
static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr)
|
||||||
#else
|
#else
|
||||||
static unsigned int test_thread(void *ptr)
|
static unsigned int test_thread(void *ptr)
|
||||||
|
|
@ -111,7 +107,7 @@ test_cleanup:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
|
#ifdef USE_THREADS
|
||||||
|
|
||||||
static void t3207_test_lock(CURL *curl, curl_lock_data data,
|
static void t3207_test_lock(CURL *curl, curl_lock_data data,
|
||||||
curl_lock_access laccess, void *useptr)
|
curl_lock_access laccess, void *useptr)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue