1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-26 00:37:43 +03:00

threads: Rework initialization

Make init/cleanup functions private. Merge xmlOnceInit into
xmlInitThreadsInternal.
This commit is contained in:
Nick Wellnhofer
2022-11-25 12:06:27 +01:00
parent 9dbf137455
commit 7010d8779b
3 changed files with 41 additions and 90 deletions

View File

@@ -5,4 +5,7 @@ void __xmlGlobalInitMutexLock(void);
void __xmlGlobalInitMutexUnlock(void); void __xmlGlobalInitMutexUnlock(void);
void __xmlGlobalInitMutexDestroy(void); void __xmlGlobalInitMutexDestroy(void);
void xmlInitThreadsInternal(void);
void xmlCleanupThreadsInternal(void);
#endif /* XML_THREADS_H_PRIVATE__ */ #endif /* XML_THREADS_H_PRIVATE__ */

View File

@@ -14495,7 +14495,7 @@ xmlInitParser(void) {
__xmlGlobalInitMutexLock(); __xmlGlobalInitMutexLock();
if (xmlParserInitialized == 0) { if (xmlParserInitialized == 0) {
#endif #endif
xmlInitThreads(); xmlInitThreadsInternal();
xmlInitGlobalsInternal(); xmlInitGlobalsInternal();
xmlInitMemoryInternal(); xmlInitMemoryInternal();
xmlInitializeDict(); xmlInitializeDict();
@@ -14555,7 +14555,7 @@ xmlCleanupParser(void) {
xmlRelaxNGCleanupTypes(); xmlRelaxNGCleanupTypes();
#endif #endif
xmlCleanupGlobalsInternal(); xmlCleanupGlobalsInternal();
xmlCleanupThreads(); /* must be last if called not from the main thread */ xmlCleanupThreadsInternal();
xmlCleanupMemoryInternal(); xmlCleanupMemoryInternal();
xmlParserInitialized = 0; xmlParserInitialized = 0;
} }

122
threads.c
View File

@@ -47,7 +47,6 @@ static int libxml_is_threaded = -1;
#define XML_PTHREAD_WEAK #define XML_PTHREAD_WEAK
#pragma weak pthread_once
#pragma weak pthread_getspecific #pragma weak pthread_getspecific
#pragma weak pthread_setspecific #pragma weak pthread_setspecific
#pragma weak pthread_key_create #pragma weak pthread_key_create
@@ -118,8 +117,6 @@ struct _xmlRMutex {
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
static pthread_key_t globalkey; static pthread_key_t globalkey;
static pthread_t mainthread; 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; static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
#elif defined HAVE_WIN32_THREADS #elif defined HAVE_WIN32_THREADS
#if defined(HAVE_COMPILER_TLS) #if defined(HAVE_COMPILER_TLS)
@@ -129,19 +126,11 @@ static __declspec(thread) int tlstate_inited = 0;
static DWORD globalkey = TLS_OUT_OF_INDEXES; static DWORD globalkey = TLS_OUT_OF_INDEXES;
#endif /* HAVE_COMPILER_TLS */ #endif /* HAVE_COMPILER_TLS */
static DWORD mainthread; static DWORD mainthread;
static struct {
DWORD done;
LONG control;
} run_once = { 0, 0};
static volatile LPCRITICAL_SECTION global_init_lock = NULL; static volatile LPCRITICAL_SECTION global_init_lock = NULL;
#endif #endif
static xmlRMutexPtr xmlLibraryLock = NULL; static xmlRMutexPtr xmlLibraryLock = NULL;
#ifdef LIBXML_THREAD_ENABLED
static void xmlOnceInit(void);
#endif
/** /**
* xmlNewMutex: * xmlNewMutex:
* *
@@ -538,8 +527,6 @@ xmlGetGlobalState(void)
if (libxml_is_threaded == 0) if (libxml_is_threaded == 0)
return (NULL); return (NULL);
pthread_once(&once_control, xmlOnceInit);
if ((globalval = (xmlGlobalState *) if ((globalval = (xmlGlobalState *)
pthread_getspecific(globalkey)) == NULL) { pthread_getspecific(globalkey)) == NULL) {
xmlGlobalState *tsd = xmlNewGlobalState(); xmlGlobalState *tsd = xmlNewGlobalState();
@@ -560,8 +547,6 @@ xmlGetGlobalState(void)
#else /* HAVE_COMPILER_TLS */ #else /* HAVE_COMPILER_TLS */
xmlGlobalState *globalval; xmlGlobalState *globalval;
xmlGlobalStateCleanupHelperParams *p; xmlGlobalStateCleanupHelperParams *p;
xmlOnceInit();
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
globalval = (xmlGlobalState *) TlsGetValue(globalkey); globalval = (xmlGlobalState *) TlsGetValue(globalkey);
#else #else
@@ -654,14 +639,10 @@ xmlGetThreadId(void)
int int
xmlIsMainThread(void) xmlIsMainThread(void)
{ {
xmlInitParser();
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded == -1)
xmlInitThreads();
if (libxml_is_threaded == 0) if (libxml_is_threaded == 0)
return (1); return (1);
pthread_once(&once_control, xmlOnceInit);
#elif defined HAVE_WIN32_THREADS
xmlOnceInit();
#endif #endif
#ifdef DEBUG_THREADS #ifdef DEBUG_THREADS
@@ -709,20 +690,26 @@ xmlUnlockLibrary(void)
/** /**
* xmlInitThreads: * xmlInitThreads:
* *
* DEPRECATED: This function will be made private. Call xmlInitParser to * DEPRECATED: Alias for xmlInitParser.
* initialize the library.
*
* xmlInitThreads() is used to to initialize all the thread related
* data of the libxml2 library.
*/ */
void void
xmlInitThreads(void) xmlInitThreads(void)
{
xmlInitParser();
}
/**
* xmlInitThreadsInternal:
*
* Used to to initialize all the thread related data.
*/
void
xmlInitThreadsInternal(void)
{ {
#ifdef HAVE_POSIX_THREADS #ifdef HAVE_POSIX_THREADS
#ifdef XML_PTHREAD_WEAK #ifdef XML_PTHREAD_WEAK
if (libxml_is_threaded == -1) { if (libxml_is_threaded == -1) {
if ((pthread_once != NULL) && if ((pthread_getspecific != NULL) &&
(pthread_getspecific != NULL) &&
(pthread_setspecific != NULL) && (pthread_setspecific != NULL) &&
(pthread_key_create != NULL) && (pthread_key_create != NULL) &&
(pthread_key_delete != NULL) && (pthread_key_delete != NULL) &&
@@ -750,38 +737,42 @@ xmlInitThreads(void)
} }
} }
#endif /* XML_PTHREAD_WEAK */ #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 #endif
} }
/** /**
* xmlCleanupThreads: * 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 * to free global state but see the warnings there. xmlCleanupParser
* should be only called once at program exit. In most cases, you don't * should be only called once at program exit. In most cases, you don't
* have call cleanup functions at all. * 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 void
xmlCleanupThreads(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 #ifdef HAVE_POSIX_THREADS
if (libxml_is_threaded != 0)
pthread_key_delete(globalkey); pthread_key_delete(globalkey);
once_control = once_control_init;
#elif defined(HAVE_WIN32_THREADS) #elif defined(HAVE_WIN32_THREADS)
#if !defined(HAVE_COMPILER_TLS) #if !defined(HAVE_COMPILER_TLS)
if (globalkey != TLS_OUT_OF_INDEXES) { if (globalkey != TLS_OUT_OF_INDEXES) {
@@ -807,52 +798,9 @@ xmlCleanupThreads(void)
DeleteCriticalSection(&cleanup_helpers_cs); DeleteCriticalSection(&cleanup_helpers_cs);
#endif #endif
#endif #endif
run_once.done = 0;
run_once.control = 0;
#endif #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: * DllMain:
* @hinstDLL: handle to DLL instance * @hinstDLL: handle to DLL instance