mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-03-27 18:50:07 +03:00
threads: Use pthread_once and InitOnceExecuteOnce
Static initialization flags aren't thread-safe. Also avoids an allocation on Windows. TODO: Breaks xmllint on Windows.
This commit is contained in:
parent
be250b798f
commit
5f3f66c683
@ -3227,6 +3227,7 @@ xmlCatalogCleanup(void) {
|
||||
void
|
||||
xmlCleanupCatalogInternal(void) {
|
||||
xmlFreeRMutex(xmlCatalogMutex);
|
||||
xmlCatalogMutex = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
12
globals.c
12
globals.c
@ -90,8 +90,6 @@ XML_GLOBALS_TREE
|
||||
#undef XML_OP
|
||||
};
|
||||
|
||||
static int parserInitialized;
|
||||
|
||||
/*
|
||||
* Mutex to protect "ForNewThreads" variables
|
||||
*/
|
||||
@ -606,8 +604,6 @@ void xmlCleanupGlobalsInternal(void) {
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
parserInitialized = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -636,10 +632,10 @@ xmlGetGlobalState(void)
|
||||
|
||||
static int
|
||||
xmlIsMainThreadInternal(void) {
|
||||
if (parserInitialized == 0) {
|
||||
xmlInitParser();
|
||||
parserInitialized = 1;
|
||||
}
|
||||
/*
|
||||
* Make sure that mainthread is initialized.
|
||||
*/
|
||||
xmlInitParser();
|
||||
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
return (pthread_equal(mainthread, pthread_self()));
|
||||
|
206
threads.c
206
threads.c
@ -374,90 +374,52 @@ xmlCleanupThreads(void)
|
||||
************************************************************************/
|
||||
|
||||
static int xmlParserInitialized = 0;
|
||||
static int xmlParserInnerInitialized = 0;
|
||||
|
||||
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_once_t onceControl = PTHREAD_ONCE_INIT;
|
||||
#elif defined HAVE_WIN32_THREADS
|
||||
static volatile LPCRITICAL_SECTION global_init_lock = NULL;
|
||||
static INIT_ONCE onceControl = INIT_ONCE_STATIC_INIT;
|
||||
#else
|
||||
static int onceControl = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* xmlGlobalInitMutexLock
|
||||
*
|
||||
* Makes sure that the global initialization mutex is initialized and
|
||||
* locks it.
|
||||
*/
|
||||
static void
|
||||
xmlGlobalInitMutexLock(void) {
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
|
||||
/* The mutex is statically initialized, so we just lock it. */
|
||||
pthread_mutex_lock(&global_init_lock);
|
||||
|
||||
#elif defined HAVE_WIN32_THREADS
|
||||
|
||||
LPCRITICAL_SECTION cs;
|
||||
|
||||
/* Create a new critical section */
|
||||
if (global_init_lock == NULL) {
|
||||
cs = malloc(sizeof(CRITICAL_SECTION));
|
||||
if (cs == NULL)
|
||||
xmlAbort("libxml2: xmlInitParser: out of memory\n");
|
||||
InitializeCriticalSection(cs);
|
||||
|
||||
/* Swap it into the global_init_lock */
|
||||
#ifdef InterlockedCompareExchangePointer
|
||||
InterlockedCompareExchangePointer((void **) &global_init_lock,
|
||||
cs, NULL);
|
||||
#else /* Use older void* version */
|
||||
InterlockedCompareExchange((void **) &global_init_lock,
|
||||
(void *) cs, NULL);
|
||||
#endif /* InterlockedCompareExchangePointer */
|
||||
|
||||
/* If another thread successfully recorded its critical
|
||||
* section in the global_init_lock then discard the one
|
||||
* allocated by this thread. */
|
||||
if (global_init_lock != cs) {
|
||||
DeleteCriticalSection(cs);
|
||||
free(cs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lock the chosen critical section */
|
||||
EnterCriticalSection(global_init_lock);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
xmlGlobalInitMutexUnlock(void) {
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
pthread_mutex_unlock(&global_init_lock);
|
||||
#elif defined HAVE_WIN32_THREADS
|
||||
if (global_init_lock != NULL)
|
||||
LeaveCriticalSection(global_init_lock);
|
||||
xmlInitParserInternal(void) {
|
||||
#if defined(_WIN32) && \
|
||||
!defined(LIBXML_THREAD_ALLOC_ENABLED) && \
|
||||
(!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
|
||||
if (xmlFree == free)
|
||||
atexit(xmlCleanupParser);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note that the initialization code must not make memory allocations.
|
||||
*/
|
||||
xmlInitRandom(); /* Required by xmlInitGlobalsInternal */
|
||||
xmlInitMemoryInternal();
|
||||
xmlInitGlobalsInternal();
|
||||
xmlInitDictInternal();
|
||||
xmlInitEncodingInternal();
|
||||
#if defined(LIBXML_XPATH_ENABLED)
|
||||
xmlInitXPathInternal();
|
||||
#endif
|
||||
xmlInitIOCallbacks();
|
||||
#ifdef LIBXML_CATALOG_ENABLED
|
||||
xmlInitCatalogInternal();
|
||||
#endif
|
||||
|
||||
xmlParserInitialized = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlGlobalInitMutexDestroy
|
||||
*
|
||||
* Makes sure that the global initialization mutex is destroyed before
|
||||
* application termination.
|
||||
*/
|
||||
static void
|
||||
xmlGlobalInitMutexDestroy(void) {
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
#elif defined HAVE_WIN32_THREADS
|
||||
if (global_init_lock != NULL) {
|
||||
DeleteCriticalSection(global_init_lock);
|
||||
free(global_init_lock);
|
||||
global_init_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_WIN32_THREADS)
|
||||
static BOOL
|
||||
xmlInitParserWinWrapper(INIT_ONCE *initOnce ATTRIBUTE_UNUSED,
|
||||
void *parameter ATTRIBUTE_UNUSED,
|
||||
void **context ATTRIBUTE_UNUSED) {
|
||||
xmlInitParserInternal();
|
||||
return(TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* xmlInitParser:
|
||||
@ -469,63 +431,32 @@ xmlGlobalInitMutexDestroy(void) {
|
||||
*/
|
||||
void
|
||||
xmlInitParser(void) {
|
||||
/*
|
||||
* Note that the initialization code must not make memory allocations.
|
||||
*/
|
||||
if (xmlParserInitialized != 0)
|
||||
return;
|
||||
|
||||
xmlGlobalInitMutexLock();
|
||||
|
||||
if (xmlParserInnerInitialized == 0) {
|
||||
#if defined(_WIN32) && \
|
||||
!defined(LIBXML_THREAD_ALLOC_ENABLED) && \
|
||||
(!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
|
||||
if (xmlFree == free)
|
||||
atexit(xmlCleanupParser);
|
||||
#endif
|
||||
|
||||
xmlInitRandom(); /* Required by xmlInitGlobalsInternal */
|
||||
xmlInitMemoryInternal();
|
||||
xmlInitGlobalsInternal();
|
||||
xmlInitDictInternal();
|
||||
xmlInitEncodingInternal();
|
||||
#if defined(LIBXML_XPATH_ENABLED)
|
||||
xmlInitXPathInternal();
|
||||
#endif
|
||||
xmlInitIOCallbacks();
|
||||
#ifdef LIBXML_CATALOG_ENABLED
|
||||
xmlInitCatalogInternal();
|
||||
#endif
|
||||
|
||||
xmlParserInnerInitialized = 1;
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
pthread_once(&onceControl, xmlInitParserInternal);
|
||||
#elif defined(HAVE_WIN32_THREADS)
|
||||
InitOnceExecuteOnce(&onceControl, xmlInitParserWinWrapper, NULL, NULL);
|
||||
#else
|
||||
if (onceControl == 0) {
|
||||
xmlInitParserInternal();
|
||||
onceControl = 1;
|
||||
}
|
||||
|
||||
xmlGlobalInitMutexUnlock();
|
||||
|
||||
xmlParserInitialized = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlCleanupParser:
|
||||
*
|
||||
* This function name is somewhat misleading. It does not clean up
|
||||
* parser state, it cleans up memory allocated by the library itself.
|
||||
* It is a cleanup function for the XML library. It tries to reclaim all
|
||||
* related global memory allocated for the library processing.
|
||||
* It doesn't deallocate any document related memory. One should
|
||||
* call xmlCleanupParser() only when the process has finished using
|
||||
* the library and all XML/HTML documents built with it.
|
||||
* See also xmlInitParser() which has the opposite function of preparing
|
||||
* the library for operations.
|
||||
* This function is named somewhat misleadingly. It does not clean up
|
||||
* parser state but global memory allocated by the library itself. This
|
||||
* function is mainly useful to avoid false positives from memory leak
|
||||
* checkers and SHOULD ONLY BE CALLED RIGHT BEFORE THE WHOLE PROCESS
|
||||
* EXITS.
|
||||
*
|
||||
* 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 !
|
||||
* WARNING: If a process is multithreaded or uses other shared or
|
||||
* dynamic libraries, calling this function may cause crashes if
|
||||
* another thread or library is still using libxml2. It can be very
|
||||
* hard to guess if libxml2 is in use by a process. In case of doubt
|
||||
* abstain from calling this function.
|
||||
*/
|
||||
void
|
||||
xmlCleanupParser(void) {
|
||||
@ -533,7 +464,6 @@ xmlCleanupParser(void) {
|
||||
return;
|
||||
|
||||
/* These functions can call xmlFree. */
|
||||
|
||||
xmlCleanupCharEncodingHandlers();
|
||||
#ifdef LIBXML_CATALOG_ENABLED
|
||||
xmlCatalogCleanup();
|
||||
@ -545,20 +475,34 @@ xmlCleanupParser(void) {
|
||||
#endif
|
||||
|
||||
/* These functions should never call xmlFree. */
|
||||
|
||||
xmlCleanupDictInternal();
|
||||
xmlCleanupRandom();
|
||||
xmlCleanupGlobalsInternal();
|
||||
|
||||
/*
|
||||
* Must come last. On Windows, xmlCleanupGlobalsInternal can call
|
||||
* xmlFree which uses xmlMemMutex in debug mode.
|
||||
* Must come last. xmlCleanupGlobalsInternal can call xmlFree which
|
||||
* uses xmlMemMutex in debug mode.
|
||||
*/
|
||||
xmlCleanupMemoryInternal();
|
||||
|
||||
xmlGlobalInitMutexDestroy();
|
||||
|
||||
xmlParserInitialized = 0;
|
||||
xmlParserInnerInitialized = 0;
|
||||
|
||||
/*
|
||||
* This is a bit sketchy but should make reinitialization work.
|
||||
*/
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
{
|
||||
pthread_once_t tmp = PTHREAD_ONCE_INIT;
|
||||
memcpy(&onceControl, &tmp, sizeof(tmp));
|
||||
}
|
||||
#elif defined(HAVE_WIN32_THREADS)
|
||||
{
|
||||
INIT_ONCE tmp = INIT_ONCE_STATIC_INIT;
|
||||
memcpy(&onceControl, &tmp, sizeof(tmp));
|
||||
}
|
||||
#else
|
||||
onceControl = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_FUNC_ATTRIBUTE_DESTRUCTOR) && \
|
||||
|
Loading…
x
Reference in New Issue
Block a user