curl-library
libcurl multithreading
Date: Fri, 22 Sep 2006 12:37:15 +0300
Hi,
I am bringing up and old issue, in the hope of getting a solution for it.
http://curl.haxx.se/mail/lib-2003-09/0134.html
http://curl.haxx.se/mail/lib-2003-09/0138.html
The problem is that without using CURLOPT_NOSIGNAL, curl just doesn't
work in a multithreaded environment: it jumps into another thread's
stack, and segfaults.
As Daniel Stenberg pointed out, we'd need to use ares, or provide our
own timeout mechanism.
However I don't understand why the suggested pthread_getspecific fix
can't be used _if_ pthreads is available. 'pthread_getspecific' is
part of POSIX Threads extension, and _if_ it is available, then you
should add support for it. It is not just adding support for some
weird threading system/API/style/whatever, it is an IEEE standard!
[http://www.opengroup.org/onlinepubs/009695399/functions/pthread_setspecific.html]
The original 'patch' needed the client to use pthread_setspecific, but
that can be moved into curl_easy_init.
What do you think of these changes below:
In hostip.c:
#ifdef HAVE_SIGSETJMP
#ifndef HAVE_PTHREADS_SPECIFIC
/* Beware this is a global and unique instance. This is used to store the
return address that we can jump back to from inside a signal handler. This
is not thread-safe stuff. */
sigjmp_buf curl_jmpenv;
# else
pthread_key_t curl_jmpenv;
# endif
#endif
and then in Curl_resolv:
#ifdef HAVE_SIGSETJMP
/* this allows us to time-out from the name resolver, as the timeout
will generate a signal and we will siglongjmp() from that here */
if(!data->set.no_signal &&
# ifndef HAVE_PTHREADS_SPECIFIC
sigsetjmp(curl_jmpenv, 1)
# else
sigsetjmp(*((sigjmp_buf*)pthread_getspecific(curl_jmpenv)), 1)
# endif
) {
/* this is coming from a siglongjmp() */
failf(data, "name lookup timed out");
return -1;
}
#endif
Similarly, in url.c:
RETSIGTYPE alarmfunc(int signal)
{
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void)signal;
#ifdef HAVE_SIGSETJMP
#ifndef HAVE_PTHREADS_SPECIFIC
siglongjmp(curl_jmpenv, 1);
# else
siglongjmp(*((sig_jmpbuf*)pthread_getspecific(curl_jmpenv)), 1);
# endif
#endif
return;
}
In easy.c:
#ifdef HAVE_SIGSETJMP
#include <setjmp.h>
#endif
#if defined(HAVE_PTHREADS_SPECIFIC) && defined(HAVE_SIGSETJMP)
extern pthread_key_t curl_jmpenv;
static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT;
static void buffer_key_alloc(void)
{
pthread_key_create(&curl_jmpenv,buffer_destroy);
}
static void buffer_destroy(void* buf)
{
free(buf);
}
#endif
in curl_easy_init():
# if defined(HAVE_PTHREADS_SPECIFIC) && defined(HAVE_SIGSETJMP)
pthread_once(&buffer_key_once,buffer_key_alloc);
pthread_setspecific(curl_jmpenv, malloc(sizeof(sigjmp_buf)));
# endif
and a function to tell the libcurl user if signal based timeouts are
thread-safe or not:
int curl_easy_aresignaltimeouts_threadsafe()
{
#ifdef HAVE_PTHREADS_SPECIFIC
return 1;
#else
return 0;
#endif
}
You should also add a check in configure.ac for
pthread_getspecific/pthread_set_specific.
Best regards,
Edwin
Received on 2006-09-22