1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-24 13:33:01 +03:00

threads: Use __libc_single_threaded if available

Fixes #427
This commit is contained in:
Nick Wellnhofer
2022-10-24 21:50:34 +02:00
parent c73d464afb
commit 71931233cd

132
threads.c
View File

@@ -25,13 +25,39 @@
/* #define DEBUG_THREADS */ /* #define DEBUG_THREADS */
#ifdef HAVE_POSIX_THREADS #if defined(HAVE_POSIX_THREADS) && \
defined(__GLIBC__) && \
__GLIBC__ * 100 + __GLIBC_MINOR__ >= 234
#if defined(__GNUC__) && defined(__linux__) /*
* The modern way available since glibc 2.32.
*
* The check above is for glibc 2.34 which merged the pthread symbols into
* libc. Since we still allow linking without pthread symbols (see below),
* this only works if pthread symbols are guaranteed to be available.
*/
static int libxml_is_threaded = -1; #include <sys/single_threaded.h>
#define XML_PTHREAD_WEAK #define XML_IS_THREADED() (!__libc_single_threaded)
#elif defined(HAVE_POSIX_THREADS) && \
defined(__GLIBC__) && \
defined(__GNUC__)
/*
* The traditional way to check for single-threaded applications with
* glibc was to check whether the separate libpthread library is
* linked in. This works by not linking libxml2 with libpthread (see
* BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring
* pthread functions as weak symbols.
*
* In glibc 2.34, the pthread symbols were moved from libpthread to libc,
* so this doesn't work anymore.
*
* At some point, this legacy code and the BASE_THREAD_LIBS hack in
* configure.ac can probably be removed.
*/
#pragma weak pthread_getspecific #pragma weak pthread_getspecific
#pragma weak pthread_setspecific #pragma weak pthread_setspecific
@@ -50,13 +76,16 @@ static int libxml_is_threaded = -1;
#pragma weak pthread_key_delete #pragma weak pthread_key_delete
#pragma weak pthread_cond_signal #pragma weak pthread_cond_signal
#else /* __GNUC__, __GLIBC__, __linux__ */ #define XML_PTHREAD_WEAK
#define XML_IS_THREADED() libxml_is_threaded
static int libxml_is_threaded = 1; static int libxml_is_threaded = -1;
#endif /* __GNUC__, __GLIBC__, __linux__ */ #else /* other POSIX platforms */
#endif /* HAVE_POSIX_THREADS */ #define XML_IS_THREADED() 1
#endif
/* /*
* TODO: this module still uses malloc/free and not xmlMalloc/xmlFree * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
@@ -187,7 +216,11 @@ xmlMutexLock(xmlMutexPtr tok)
if (tok == NULL) if (tok == NULL)
return; return;
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded != 0) /*
* This assumes that __libc_single_threaded won't change while the
* lock is held.
*/
if (XML_IS_THREADED() != 0)
pthread_mutex_lock(&tok->lock); pthread_mutex_lock(&tok->lock);
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
EnterCriticalSection(&tok->cs); EnterCriticalSection(&tok->cs);
@@ -207,7 +240,7 @@ xmlMutexUnlock(xmlMutexPtr tok)
if (tok == NULL) if (tok == NULL)
return; return;
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded != 0) if (XML_IS_THREADED() != 0)
pthread_mutex_unlock(&tok->lock); pthread_mutex_unlock(&tok->lock);
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
LeaveCriticalSection(&tok->cs); LeaveCriticalSection(&tok->cs);
@@ -232,12 +265,10 @@ xmlNewRMutex(void)
if ((tok = malloc(sizeof(xmlRMutex))) == NULL) if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
return (NULL); return (NULL);
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded != 0) { pthread_mutex_init(&tok->lock, NULL);
pthread_mutex_init(&tok->lock, NULL); tok->held = 0;
tok->held = 0; tok->waiters = 0;
tok->waiters = 0; pthread_cond_init(&tok->cv, NULL);
pthread_cond_init(&tok->cv, NULL);
}
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
InitializeCriticalSection(&tok->cs); InitializeCriticalSection(&tok->cs);
#endif #endif
@@ -257,10 +288,8 @@ xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
if (tok == NULL) if (tok == NULL)
return; return;
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded != 0) { pthread_mutex_destroy(&tok->lock);
pthread_mutex_destroy(&tok->lock); pthread_cond_destroy(&tok->cv);
pthread_cond_destroy(&tok->cv);
}
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
DeleteCriticalSection(&tok->cs); DeleteCriticalSection(&tok->cs);
#endif #endif
@@ -279,7 +308,7 @@ xmlRMutexLock(xmlRMutexPtr tok)
if (tok == NULL) if (tok == NULL)
return; return;
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded == 0) if (XML_IS_THREADED() == 0)
return; return;
pthread_mutex_lock(&tok->lock); pthread_mutex_lock(&tok->lock);
@@ -315,7 +344,7 @@ xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
if (tok == NULL) if (tok == NULL)
return; return;
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded == 0) if (XML_IS_THREADED() == 0)
return; return;
pthread_mutex_lock(&tok->lock); pthread_mutex_lock(&tok->lock);
@@ -342,11 +371,14 @@ __xmlGlobalInitMutexLock(void)
{ {
/* Make sure the global init lock is initialized and then lock it. */ /* Make sure the global init lock is initialized and then lock it. */
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
/* The mutex is statically initialized, so we just lock it. */
#ifdef XML_PTHREAD_WEAK #ifdef XML_PTHREAD_WEAK
if (pthread_mutex_lock == NULL) if (pthread_mutex_lock == NULL)
return; return;
#endif /* XML_PTHREAD_WEAK */ #else
if (XML_IS_THREADED() == 0)
return;
#endif
/* The mutex is statically initialized, so we just lock it. */
pthread_mutex_lock(&global_init_lock); pthread_mutex_lock(&global_init_lock);
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
LPCRITICAL_SECTION cs; LPCRITICAL_SECTION cs;
@@ -389,9 +421,12 @@ __xmlGlobalInitMutexUnlock(void)
{ {
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
#ifdef XML_PTHREAD_WEAK #ifdef XML_PTHREAD_WEAK
if (pthread_mutex_unlock == NULL) if (pthread_mutex_lock == NULL)
return; return;
#endif /* XML_PTHREAD_WEAK */ #else
if (XML_IS_THREADED() == 0)
return;
#endif
pthread_mutex_unlock(&global_init_lock); pthread_mutex_unlock(&global_init_lock);
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
if (global_init_lock != NULL) { if (global_init_lock != NULL) {
@@ -524,7 +559,7 @@ xmlGetGlobalState(void)
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
xmlGlobalState *globalval; xmlGlobalState *globalval;
if (libxml_is_threaded == 0) if (XML_IS_THREADED() == 0)
return (NULL); return (NULL);
if ((globalval = (xmlGlobalState *) if ((globalval = (xmlGlobalState *)
@@ -618,7 +653,7 @@ xmlGetThreadId(void)
pthread_t id; pthread_t id;
int ret; int ret;
if (libxml_is_threaded == 0) if (XML_IS_THREADED() == 0)
return (0); return (0);
id = pthread_self(); id = pthread_self();
/* horrible but preserves compat, see warning above */ /* horrible but preserves compat, see warning above */
@@ -644,15 +679,13 @@ int
xmlIsMainThread(void) xmlIsMainThread(void)
{ {
xmlInitParser(); xmlInitParser();
#ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded == 0)
return (1);
#endif
#ifdef DEBUG_THREADS #ifdef DEBUG_THREADS
xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
#endif #endif
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (XML_IS_THREADED() == 0)
return (1);
return (pthread_equal(mainthread,pthread_self())); return (pthread_equal(mainthread,pthread_self()));
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
return (mainthread == GetCurrentThreadId()); return (mainthread == GetCurrentThreadId());
@@ -712,34 +745,13 @@ xmlInitThreadsInternal(void)
{ {
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
#ifdef XML_PTHREAD_WEAK #ifdef XML_PTHREAD_WEAK
if (libxml_is_threaded == -1) { /*
if ((pthread_getspecific != NULL) && * This is somewhat unreliable since libpthread could be loaded
(pthread_setspecific != NULL) && * later with dlopen() and threads could be created. But it's
(pthread_key_create != NULL) && * long-standing behavior and hard to work around.
(pthread_key_delete != NULL) && */
(pthread_mutex_init != NULL) && if (libxml_is_threaded == -1)
(pthread_mutex_destroy != NULL) && libxml_is_threaded = (pthread_mutex_lock != NULL);
(pthread_mutex_lock != NULL) &&
(pthread_mutex_unlock != NULL) &&
(pthread_cond_init != NULL) &&
(pthread_cond_destroy != NULL) &&
(pthread_cond_wait != NULL) &&
/*
* pthread_equal can be inline, resuting in -Waddress warnings.
* Let's assume it's available if all the other functions are.
*/
/* (pthread_equal != NULL) && */
(pthread_self != NULL) &&
(pthread_cond_signal != NULL)) {
libxml_is_threaded = 1;
/* fprintf(stderr, "Running multithreaded\n"); */
} else {
/* fprintf(stderr, "Running without multithread\n"); */
libxml_is_threaded = 0;
}
}
#endif /* XML_PTHREAD_WEAK */ #endif /* XML_PTHREAD_WEAK */
pthread_key_create(&globalkey, xmlFreeGlobalState); pthread_key_create(&globalkey, xmlFreeGlobalState);
mainthread = pthread_self(); mainthread = pthread_self();