From 7010d8779b5cb1a78f6c7cc9a067eb655649e114 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 25 Nov 2022 12:06:27 +0100 Subject: [PATCH] threads: Rework initialization Make init/cleanup functions private. Merge xmlOnceInit into xmlInitThreadsInternal. --- include/private/threads.h | 3 + parser.c | 4 +- threads.c | 124 +++++++++++--------------------------- 3 files changed, 41 insertions(+), 90 deletions(-) diff --git a/include/private/threads.h b/include/private/threads.h index c054a6fb..59dbab10 100644 --- a/include/private/threads.h +++ b/include/private/threads.h @@ -5,4 +5,7 @@ void __xmlGlobalInitMutexLock(void); void __xmlGlobalInitMutexUnlock(void); void __xmlGlobalInitMutexDestroy(void); +void xmlInitThreadsInternal(void); +void xmlCleanupThreadsInternal(void); + #endif /* XML_THREADS_H_PRIVATE__ */ diff --git a/parser.c b/parser.c index 8c53fd6d..78fb6427 100644 --- a/parser.c +++ b/parser.c @@ -14495,7 +14495,7 @@ xmlInitParser(void) { __xmlGlobalInitMutexLock(); if (xmlParserInitialized == 0) { #endif - xmlInitThreads(); + xmlInitThreadsInternal(); xmlInitGlobalsInternal(); xmlInitMemoryInternal(); xmlInitializeDict(); @@ -14555,7 +14555,7 @@ xmlCleanupParser(void) { xmlRelaxNGCleanupTypes(); #endif xmlCleanupGlobalsInternal(); - xmlCleanupThreads(); /* must be last if called not from the main thread */ + xmlCleanupThreadsInternal(); xmlCleanupMemoryInternal(); xmlParserInitialized = 0; } diff --git a/threads.c b/threads.c index 2f9952c2..69dfcffd 100644 --- a/threads.c +++ b/threads.c @@ -47,7 +47,6 @@ static int libxml_is_threaded = -1; #define XML_PTHREAD_WEAK -#pragma weak pthread_once #pragma weak pthread_getspecific #pragma weak pthread_setspecific #pragma weak pthread_key_create @@ -118,8 +117,6 @@ struct _xmlRMutex { #ifdef HAVE_POSIX_THREADS static pthread_key_t globalkey; static pthread_t mainthread; -static pthread_once_t once_control = PTHREAD_ONCE_INIT; -static pthread_once_t once_control_init = PTHREAD_ONCE_INIT; static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; #elif defined HAVE_WIN32_THREADS #if defined(HAVE_COMPILER_TLS) @@ -129,19 +126,11 @@ static __declspec(thread) int tlstate_inited = 0; static DWORD globalkey = TLS_OUT_OF_INDEXES; #endif /* HAVE_COMPILER_TLS */ static DWORD mainthread; -static struct { - DWORD done; - LONG control; -} run_once = { 0, 0}; static volatile LPCRITICAL_SECTION global_init_lock = NULL; #endif static xmlRMutexPtr xmlLibraryLock = NULL; -#ifdef LIBXML_THREAD_ENABLED -static void xmlOnceInit(void); -#endif - /** * xmlNewMutex: * @@ -538,8 +527,6 @@ xmlGetGlobalState(void) if (libxml_is_threaded == 0) return (NULL); - pthread_once(&once_control, xmlOnceInit); - if ((globalval = (xmlGlobalState *) pthread_getspecific(globalkey)) == NULL) { xmlGlobalState *tsd = xmlNewGlobalState(); @@ -560,8 +547,6 @@ xmlGetGlobalState(void) #else /* HAVE_COMPILER_TLS */ xmlGlobalState *globalval; xmlGlobalStateCleanupHelperParams *p; - - xmlOnceInit(); #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) globalval = (xmlGlobalState *) TlsGetValue(globalkey); #else @@ -654,14 +639,10 @@ xmlGetThreadId(void) int xmlIsMainThread(void) { + xmlInitParser(); #ifdef HAVE_POSIX_THREADS - if (libxml_is_threaded == -1) - xmlInitThreads(); if (libxml_is_threaded == 0) return (1); - pthread_once(&once_control, xmlOnceInit); -#elif defined HAVE_WIN32_THREADS - xmlOnceInit(); #endif #ifdef DEBUG_THREADS @@ -709,20 +690,26 @@ xmlUnlockLibrary(void) /** * xmlInitThreads: * - * DEPRECATED: This function will be made private. Call xmlInitParser to - * initialize the library. - * - * xmlInitThreads() is used to to initialize all the thread related - * data of the libxml2 library. + * DEPRECATED: Alias for xmlInitParser. */ void xmlInitThreads(void) +{ + xmlInitParser(); +} + +/** + * xmlInitThreadsInternal: + * + * Used to to initialize all the thread related data. + */ +void +xmlInitThreadsInternal(void) { #ifdef HAVE_POSIX_THREADS #ifdef XML_PTHREAD_WEAK if (libxml_is_threaded == -1) { - if ((pthread_once != NULL) && - (pthread_getspecific != NULL) && + if ((pthread_getspecific != NULL) && (pthread_setspecific != NULL) && (pthread_key_create != NULL) && (pthread_key_delete != NULL) && @@ -750,38 +737,42 @@ xmlInitThreads(void) } } #endif /* XML_PTHREAD_WEAK */ + pthread_key_create(&globalkey, xmlFreeGlobalState); + mainthread = pthread_self(); +#elif defined(HAVE_WIN32_THREADS) +#if !defined(HAVE_COMPILER_TLS) +#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL) + InitializeCriticalSection(&cleanup_helpers_cs); +#endif + globalkey = TlsAlloc(); +#endif + mainthread = GetCurrentThreadId(); #endif } /** * xmlCleanupThreads: * - * DEPRECATED: This function will be made private. Call xmlCleanupParser + * DEPRECATED: This function is a no-op. Call xmlCleanupParser * to free global state but see the warnings there. xmlCleanupParser * should be only called once at program exit. In most cases, you don't * have call cleanup functions at all. - * - * xmlCleanupThreads() is used to to cleanup all the thread related - * data of the libxml2 library once processing has ended. - * - * WARNING: if your application is multithreaded or has plugin support - * calling this may crash the application if another thread or - * a plugin is still using libxml2. It's sometimes very hard to - * guess if libxml2 is in use in the application, some libraries - * or plugins may use it without notice. In case of doubt abstain - * from calling this function or do it just before calling exit() - * to avoid leak reports from valgrind ! */ void xmlCleanupThreads(void) { -#ifdef DEBUG_THREADS - xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); -#endif +} + +/** + * xmlCleanupThreadsInternal: + * + * Used to to cleanup all the thread related data. + */ +void +xmlCleanupThreadsInternal(void) +{ #ifdef HAVE_POSIX_THREADS - if (libxml_is_threaded != 0) - pthread_key_delete(globalkey); - once_control = once_control_init; + pthread_key_delete(globalkey); #elif defined(HAVE_WIN32_THREADS) #if !defined(HAVE_COMPILER_TLS) if (globalkey != TLS_OUT_OF_INDEXES) { @@ -807,52 +798,9 @@ xmlCleanupThreads(void) DeleteCriticalSection(&cleanup_helpers_cs); #endif #endif - run_once.done = 0; - run_once.control = 0; #endif } -#ifdef LIBXML_THREAD_ENABLED - -/** - * xmlOnceInit - * - * xmlOnceInit() is used to initialize the value of mainthread for use - * in other routines. This function should only be called using - * pthread_once() in association with the once_control variable to ensure - * that the function is only called once. See man pthread_once for more - * details. - */ -static void -xmlOnceInit(void) -{ -#ifdef HAVE_POSIX_THREADS - (void) pthread_key_create(&globalkey, xmlFreeGlobalState); - mainthread = pthread_self(); - __xmlInitializeDict(); -#elif defined(HAVE_WIN32_THREADS) - if (!run_once.done) { - if (InterlockedIncrement(&run_once.control) == 1) { -#if !defined(HAVE_COMPILER_TLS) -#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL) - InitializeCriticalSection(&cleanup_helpers_cs); -#endif - globalkey = TlsAlloc(); -#endif - mainthread = GetCurrentThreadId(); - __xmlInitializeDict(); - run_once.done = 1; - } else { - /* Another thread is working; give up our slice and - * wait until they're done. */ - while (!run_once.done) - Sleep(0); - } - } -#endif -} -#endif - /** * DllMain: * @hinstDLL: handle to DLL instance