mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2026-01-26 21:41:34 +03:00
globals: Also use thread-specific storage on "main" thread
Don't treat "main" thread specially. This simplifies access to thread-specific data. xmlGetGlobalState can now also fail on the former main thread, leading to an unrecoverable condition if malloc fails. The globals were never defined in public header files when compiling with thread support. Now they're only defined in a legacy build. Move TlsFree to DllMain to make cleanup more robust on Windows. Obsoletes #1.
This commit is contained in:
187
globals.c
187
globals.c
@@ -31,6 +31,11 @@
|
|||||||
#include "private/threads.h"
|
#include "private/threads.h"
|
||||||
#include "private/tree.h"
|
#include "private/tree.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex to protect "ForNewThreads" variables
|
||||||
|
*/
|
||||||
|
static xmlMutex xmlThrDefMutex;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thread-local storage emulation.
|
* Thread-local storage emulation.
|
||||||
*
|
*
|
||||||
@@ -54,14 +59,7 @@
|
|||||||
* function for static builds.
|
* function for static builds.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Helpful Macro
|
|
||||||
*/
|
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
#ifdef LIBXML_THREAD_ENABLED
|
||||||
#define IS_MAIN_THREAD (xmlIsMainThreadInternal())
|
|
||||||
#else
|
|
||||||
#define IS_MAIN_THREAD 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define XML_DECLARE_MEMBER(name, type, attrs) \
|
#define XML_DECLARE_MEMBER(name, type, attrs) \
|
||||||
type gs_##name;
|
type gs_##name;
|
||||||
@@ -83,20 +81,13 @@ struct _xmlGlobalState {
|
|||||||
|
|
||||||
#define XML_OP XML_DECLARE_MEMBER
|
#define XML_OP XML_DECLARE_MEMBER
|
||||||
XML_GLOBALS_ALLOC
|
XML_GLOBALS_ALLOC
|
||||||
XML_GLOBALS_ERROR
|
|
||||||
XML_GLOBALS_IO
|
|
||||||
XML_GLOBALS_PARSER
|
XML_GLOBALS_PARSER
|
||||||
|
XML_GLOBALS_ERROR
|
||||||
XML_GLOBALS_TREE
|
XML_GLOBALS_TREE
|
||||||
|
XML_GLOBALS_IO
|
||||||
#undef XML_OP
|
#undef XML_OP
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Mutex to protect "ForNewThreads" variables
|
|
||||||
*/
|
|
||||||
static xmlMutex xmlThrDefMutex;
|
|
||||||
|
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On Darwin, thread-local storage destructors seem to be run before
|
* On Darwin, thread-local storage destructors seem to be run before
|
||||||
* pthread thread-specific data destructors. This causes ASan to
|
* pthread thread-specific data destructors. This causes ASan to
|
||||||
@@ -124,14 +115,12 @@ static XML_THREAD_LOCAL xmlGlobalState globalState;
|
|||||||
* thread exit.
|
* thread exit.
|
||||||
*/
|
*/
|
||||||
static pthread_key_t globalkey;
|
static pthread_key_t globalkey;
|
||||||
static pthread_t mainthread;
|
|
||||||
|
|
||||||
#elif defined HAVE_WIN32_THREADS
|
#elif defined HAVE_WIN32_THREADS
|
||||||
|
|
||||||
#ifndef USE_TLS
|
#ifndef USE_TLS
|
||||||
static DWORD globalkey = TLS_OUT_OF_INDEXES;
|
static DWORD globalkey = TLS_OUT_OF_INDEXES;
|
||||||
#endif
|
#endif
|
||||||
static DWORD mainthread;
|
|
||||||
|
|
||||||
#endif /* HAVE_WIN32_THREADS */
|
#endif /* HAVE_WIN32_THREADS */
|
||||||
|
|
||||||
@@ -146,10 +135,6 @@ xmlFreeGlobalState(void *state);
|
|||||||
* *
|
* *
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
|
||||||
static unsigned xmlMainThreadRngState[2];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Memory allocation routines
|
* Memory allocation routines
|
||||||
*/
|
*/
|
||||||
@@ -255,7 +240,9 @@ const int xmlParserDebugEntities = 0;
|
|||||||
* Global setting, indicate that the parser should work in validating mode.
|
* Global setting, indicate that the parser should work in validating mode.
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlDoValidityCheckingDefaultValue = 0;
|
int xmlDoValidityCheckingDefaultValue = 0;
|
||||||
|
#endif
|
||||||
static int xmlDoValidityCheckingDefaultValueThrDef = 0;
|
static int xmlDoValidityCheckingDefaultValueThrDef = 0;
|
||||||
/**
|
/**
|
||||||
* xmlGetWarningsDefaultValue:
|
* xmlGetWarningsDefaultValue:
|
||||||
@@ -265,7 +252,9 @@ static int xmlDoValidityCheckingDefaultValueThrDef = 0;
|
|||||||
* Global setting, indicate that the DTD validation should provide warnings.
|
* Global setting, indicate that the DTD validation should provide warnings.
|
||||||
* Activated by default.
|
* Activated by default.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlGetWarningsDefaultValue = 1;
|
int xmlGetWarningsDefaultValue = 1;
|
||||||
|
#endif
|
||||||
static int xmlGetWarningsDefaultValueThrDef = 1;
|
static int xmlGetWarningsDefaultValueThrDef = 1;
|
||||||
/**
|
/**
|
||||||
* xmlLoadExtDtdDefaultValue:
|
* xmlLoadExtDtdDefaultValue:
|
||||||
@@ -276,7 +265,9 @@ static int xmlGetWarningsDefaultValueThrDef = 1;
|
|||||||
* validating.
|
* validating.
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlLoadExtDtdDefaultValue = 0;
|
int xmlLoadExtDtdDefaultValue = 0;
|
||||||
|
#endif
|
||||||
static int xmlLoadExtDtdDefaultValueThrDef = 0;
|
static int xmlLoadExtDtdDefaultValueThrDef = 0;
|
||||||
/**
|
/**
|
||||||
* xmlPedanticParserDefaultValue:
|
* xmlPedanticParserDefaultValue:
|
||||||
@@ -286,7 +277,9 @@ static int xmlLoadExtDtdDefaultValueThrDef = 0;
|
|||||||
* Global setting, indicate that the parser be pedantic
|
* Global setting, indicate that the parser be pedantic
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlPedanticParserDefaultValue = 0;
|
int xmlPedanticParserDefaultValue = 0;
|
||||||
|
#endif
|
||||||
static int xmlPedanticParserDefaultValueThrDef = 0;
|
static int xmlPedanticParserDefaultValueThrDef = 0;
|
||||||
/**
|
/**
|
||||||
* xmlLineNumbersDefaultValue:
|
* xmlLineNumbersDefaultValue:
|
||||||
@@ -298,7 +291,9 @@ static int xmlPedanticParserDefaultValueThrDef = 0;
|
|||||||
* Disabled by default since this may not be safe for old classes of
|
* Disabled by default since this may not be safe for old classes of
|
||||||
* application.
|
* application.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlLineNumbersDefaultValue = 0;
|
int xmlLineNumbersDefaultValue = 0;
|
||||||
|
#endif
|
||||||
static int xmlLineNumbersDefaultValueThrDef = 0;
|
static int xmlLineNumbersDefaultValueThrDef = 0;
|
||||||
/**
|
/**
|
||||||
* xmlKeepBlanksDefaultValue:
|
* xmlKeepBlanksDefaultValue:
|
||||||
@@ -311,7 +306,9 @@ static int xmlLineNumbersDefaultValueThrDef = 0;
|
|||||||
* conformant to the XML Recommendation, however the option is kept
|
* conformant to the XML Recommendation, however the option is kept
|
||||||
* for some applications since this was libxml1 default behaviour.
|
* for some applications since this was libxml1 default behaviour.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlKeepBlanksDefaultValue = 1;
|
int xmlKeepBlanksDefaultValue = 1;
|
||||||
|
#endif
|
||||||
static int xmlKeepBlanksDefaultValueThrDef = 1;
|
static int xmlKeepBlanksDefaultValueThrDef = 1;
|
||||||
/**
|
/**
|
||||||
* xmlSubstituteEntitiesDefaultValue:
|
* xmlSubstituteEntitiesDefaultValue:
|
||||||
@@ -324,7 +321,9 @@ static int xmlKeepBlanksDefaultValueThrDef = 1;
|
|||||||
* the XPath data model requires entities replacement and the XPath
|
* the XPath data model requires entities replacement and the XPath
|
||||||
* engine does not handle entities references transparently.
|
* engine does not handle entities references transparently.
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlSubstituteEntitiesDefaultValue = 0;
|
int xmlSubstituteEntitiesDefaultValue = 0;
|
||||||
|
#endif
|
||||||
static int xmlSubstituteEntitiesDefaultValueThrDef = 0;
|
static int xmlSubstituteEntitiesDefaultValueThrDef = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,7 +331,9 @@ static int xmlSubstituteEntitiesDefaultValueThrDef = 0;
|
|||||||
*
|
*
|
||||||
* DEPRECATED: Don't use
|
* DEPRECATED: Don't use
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL;
|
xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL;
|
||||||
|
#endif
|
||||||
static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL;
|
static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,7 +341,9 @@ static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL;
|
|||||||
*
|
*
|
||||||
* DEPRECATED: Don't use
|
* DEPRECATED: Don't use
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL;
|
xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL;
|
||||||
|
#endif
|
||||||
static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL;
|
static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -348,16 +351,23 @@ static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL;
|
|||||||
*
|
*
|
||||||
* DEPRECATED: Don't use
|
* DEPRECATED: Don't use
|
||||||
*/
|
*/
|
||||||
xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue = NULL;
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
static xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValueThrDef = NULL;
|
xmlParserInputBufferCreateFilenameFunc
|
||||||
|
xmlParserInputBufferCreateFilenameValue = NULL;
|
||||||
|
#endif
|
||||||
|
static xmlParserInputBufferCreateFilenameFunc
|
||||||
|
xmlParserInputBufferCreateFilenameValueThrDef = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlOutputBufferCreateFilenameValue:
|
* xmlOutputBufferCreateFilenameValue:
|
||||||
*
|
*
|
||||||
* DEPRECATED: Don't use
|
* DEPRECATED: Don't use
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue = NULL;
|
xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue = NULL;
|
||||||
static xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValueThrDef = NULL;
|
#endif
|
||||||
|
static xmlOutputBufferCreateFilenameFunc
|
||||||
|
xmlOutputBufferCreateFilenameValueThrDef = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlGenericError:
|
* xmlGenericError:
|
||||||
@@ -366,7 +376,9 @@ static xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValueThrDe
|
|||||||
*
|
*
|
||||||
* Global setting: function used for generic error callbacks
|
* Global setting: function used for generic error callbacks
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc;
|
xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc;
|
||||||
|
#endif
|
||||||
static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
|
static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
|
||||||
/**
|
/**
|
||||||
* xmlStructuredError:
|
* xmlStructuredError:
|
||||||
@@ -375,7 +387,9 @@ static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
|
|||||||
*
|
*
|
||||||
* Global setting: function used for structured error callbacks
|
* Global setting: function used for structured error callbacks
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlStructuredErrorFunc xmlStructuredError = NULL;
|
xmlStructuredErrorFunc xmlStructuredError = NULL;
|
||||||
|
#endif
|
||||||
static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL;
|
static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL;
|
||||||
/**
|
/**
|
||||||
* xmlGenericErrorContext:
|
* xmlGenericErrorContext:
|
||||||
@@ -384,7 +398,9 @@ static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL;
|
|||||||
*
|
*
|
||||||
* Global setting passed to generic error callbacks
|
* Global setting passed to generic error callbacks
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
void *xmlGenericErrorContext = NULL;
|
void *xmlGenericErrorContext = NULL;
|
||||||
|
#endif
|
||||||
static void *xmlGenericErrorContextThrDef = NULL;
|
static void *xmlGenericErrorContextThrDef = NULL;
|
||||||
/**
|
/**
|
||||||
* xmlStructuredErrorContext:
|
* xmlStructuredErrorContext:
|
||||||
@@ -393,9 +409,13 @@ static void *xmlGenericErrorContextThrDef = NULL;
|
|||||||
*
|
*
|
||||||
* Global setting passed to structured error callbacks
|
* Global setting passed to structured error callbacks
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
void *xmlStructuredErrorContext = NULL;
|
void *xmlStructuredErrorContext = NULL;
|
||||||
|
#endif
|
||||||
static void *xmlStructuredErrorContextThrDef = NULL;
|
static void *xmlStructuredErrorContextThrDef = NULL;
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
xmlError xmlLastError;
|
xmlError xmlLastError;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LIBXML_OUTPUT_ENABLED
|
#ifdef LIBXML_OUTPUT_ENABLED
|
||||||
/*
|
/*
|
||||||
@@ -409,7 +429,9 @@ xmlError xmlLastError;
|
|||||||
* Global setting, asking the serializer to indent the output tree by default
|
* Global setting, asking the serializer to indent the output tree by default
|
||||||
* Enabled by default
|
* Enabled by default
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlIndentTreeOutput = 1;
|
int xmlIndentTreeOutput = 1;
|
||||||
|
#endif
|
||||||
static int xmlIndentTreeOutputThrDef = 1;
|
static int xmlIndentTreeOutputThrDef = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,7 +442,9 @@ static int xmlIndentTreeOutputThrDef = 1;
|
|||||||
* The string used to do one-level indent. By default is equal to
|
* The string used to do one-level indent. By default is equal to
|
||||||
* " " (two spaces)
|
* " " (two spaces)
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
const char *xmlTreeIndentString = " ";
|
const char *xmlTreeIndentString = " ";
|
||||||
|
#endif
|
||||||
static const char *xmlTreeIndentStringThrDef = " ";
|
static const char *xmlTreeIndentStringThrDef = " ";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -433,7 +457,9 @@ static const char *xmlTreeIndentStringThrDef = " ";
|
|||||||
* once parsed.
|
* once parsed.
|
||||||
* Disabled by default
|
* Disabled by default
|
||||||
*/
|
*/
|
||||||
|
#if !defined(LIBXML_THREAD_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
|
||||||
int xmlSaveNoEmptyTags = 0;
|
int xmlSaveNoEmptyTags = 0;
|
||||||
|
#endif
|
||||||
static int xmlSaveNoEmptyTagsThrDef = 0;
|
static int xmlSaveNoEmptyTagsThrDef = 0;
|
||||||
#endif /* LIBXML_OUTPUT_ENABLED */
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
||||||
|
|
||||||
@@ -559,17 +585,11 @@ void xmlInitGlobalsInternal(void) {
|
|||||||
|
|
||||||
#ifdef HAVE_POSIX_THREADS
|
#ifdef HAVE_POSIX_THREADS
|
||||||
pthread_key_create(&globalkey, xmlFreeGlobalState);
|
pthread_key_create(&globalkey, xmlFreeGlobalState);
|
||||||
mainthread = pthread_self();
|
|
||||||
#elif defined(HAVE_WIN32_THREADS)
|
#elif defined(HAVE_WIN32_THREADS)
|
||||||
#ifndef USE_TLS
|
#ifndef USE_TLS
|
||||||
globalkey = TlsAlloc();
|
if (globalkey == TLS_OUT_OF_INDEXES)
|
||||||
|
globalkey = TlsAlloc();
|
||||||
#endif
|
#endif
|
||||||
mainthread = GetCurrentThreadId();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
|
||||||
xmlMainThreadRngState[0] = xmlGlobalRandom();
|
|
||||||
xmlMainThreadRngState[1] = xmlGlobalRandom();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,20 +610,34 @@ void xmlCleanupGlobals(void) {
|
|||||||
* Additional cleanup for multi-threading
|
* Additional cleanup for multi-threading
|
||||||
*/
|
*/
|
||||||
void xmlCleanupGlobalsInternal(void) {
|
void xmlCleanupGlobalsInternal(void) {
|
||||||
xmlResetError(&xmlLastError);
|
/*
|
||||||
|
* We assume that all other threads using the library have
|
||||||
xmlCleanupMutex(&xmlThrDefMutex);
|
* terminated and the last remaining thread calls
|
||||||
|
* xmlCleanupParser.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_THREADS
|
#ifdef HAVE_POSIX_THREADS
|
||||||
|
/*
|
||||||
|
* Free thread-specific data of last thread before calling
|
||||||
|
* pthread_key_delete.
|
||||||
|
*/
|
||||||
|
xmlGlobalState *gs = pthread_getspecific(globalkey);
|
||||||
|
if (gs != NULL)
|
||||||
|
xmlFreeGlobalState(gs);
|
||||||
pthread_key_delete(globalkey);
|
pthread_key_delete(globalkey);
|
||||||
#elif defined(HAVE_WIN32_THREADS)
|
#elif defined(HAVE_WIN32_THREADS)
|
||||||
#ifndef USE_TLS
|
#if !defined(USE_TLS) && \
|
||||||
|
defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
|
||||||
if (globalkey != TLS_OUT_OF_INDEXES) {
|
if (globalkey != TLS_OUT_OF_INDEXES) {
|
||||||
TlsFree(globalkey);
|
TlsFree(globalkey);
|
||||||
globalkey = TLS_OUT_OF_INDEXES;
|
globalkey = TLS_OUT_OF_INDEXES;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#else /* no thread support */
|
||||||
|
xmlResetError(&xmlLastError);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
xmlCleanupMutex(&xmlThrDefMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -630,22 +664,6 @@ xmlGetGlobalState(void)
|
|||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
xmlIsMainThreadInternal(void) {
|
|
||||||
/*
|
|
||||||
* Make sure that mainthread is initialized.
|
|
||||||
*/
|
|
||||||
xmlInitParser();
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_THREADS
|
|
||||||
return (pthread_equal(mainthread, pthread_self()));
|
|
||||||
#elif defined HAVE_WIN32_THREADS
|
|
||||||
return (mainthread == GetCurrentThreadId());
|
|
||||||
#else
|
|
||||||
return (1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlIsMainThread:
|
* xmlIsMainThread:
|
||||||
*
|
*
|
||||||
@@ -657,7 +675,7 @@ xmlIsMainThreadInternal(void) {
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmlIsMainThread(void) {
|
xmlIsMainThread(void) {
|
||||||
return(xmlIsMainThreadInternal());
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
#ifdef LIBXML_THREAD_ENABLED
|
||||||
@@ -719,42 +737,49 @@ xmlRegisterGlobalStateDtor(xmlGlobalState *gs) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
xmlInitGlobalState(xmlGlobalStatePtr gs) {
|
xmlInitGlobalState(xmlGlobalStatePtr gs) {
|
||||||
xmlMutexLock(&xmlThrDefMutex);
|
|
||||||
|
|
||||||
gs->localRngState[0] = xmlGlobalRandom();
|
gs->localRngState[0] = xmlGlobalRandom();
|
||||||
gs->localRngState[1] = xmlGlobalRandom();
|
gs->localRngState[1] = xmlGlobalRandom();
|
||||||
|
|
||||||
memset(&gs->lastError, 0, sizeof(xmlError));
|
memset(&gs->lastError, 0, sizeof(xmlError));
|
||||||
|
|
||||||
gs->gs_xmlDoValidityCheckingDefaultValue =
|
|
||||||
xmlDoValidityCheckingDefaultValueThrDef;
|
|
||||||
#ifdef LIBXML_THREAD_ALLOC_ENABLED
|
#ifdef LIBXML_THREAD_ALLOC_ENABLED
|
||||||
|
/* XML_GLOBALS_ALLOC */
|
||||||
gs->gs_xmlFree = free;
|
gs->gs_xmlFree = free;
|
||||||
gs->gs_xmlMalloc = malloc;
|
gs->gs_xmlMalloc = malloc;
|
||||||
gs->gs_xmlMallocAtomic = malloc;
|
gs->gs_xmlMallocAtomic = malloc;
|
||||||
gs->gs_xmlRealloc = realloc;
|
gs->gs_xmlRealloc = realloc;
|
||||||
gs->gs_xmlMemStrdup = xmlPosixStrdup;
|
gs->gs_xmlMemStrdup = xmlPosixStrdup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
xmlMutexLock(&xmlThrDefMutex);
|
||||||
|
|
||||||
|
/* XML_GLOBALS_PARSER */
|
||||||
|
gs->gs_xmlDoValidityCheckingDefaultValue =
|
||||||
|
xmlDoValidityCheckingDefaultValueThrDef;
|
||||||
gs->gs_xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef;
|
gs->gs_xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef;
|
||||||
#ifdef LIBXML_OUTPUT_ENABLED
|
|
||||||
gs->gs_xmlIndentTreeOutput = xmlIndentTreeOutputThrDef;
|
|
||||||
gs->gs_xmlTreeIndentString = xmlTreeIndentStringThrDef;
|
|
||||||
gs->gs_xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef;
|
|
||||||
#endif
|
|
||||||
gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
|
gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
|
||||||
gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef;
|
gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef;
|
||||||
gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
|
gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
|
||||||
gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
|
gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
|
||||||
gs->gs_xmlSubstituteEntitiesDefaultValue =
|
gs->gs_xmlSubstituteEntitiesDefaultValue =
|
||||||
xmlSubstituteEntitiesDefaultValueThrDef;
|
xmlSubstituteEntitiesDefaultValueThrDef;
|
||||||
|
#ifdef LIBXML_OUTPUT_ENABLED
|
||||||
|
gs->gs_xmlIndentTreeOutput = xmlIndentTreeOutputThrDef;
|
||||||
|
gs->gs_xmlTreeIndentString = xmlTreeIndentStringThrDef;
|
||||||
|
gs->gs_xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* XML_GLOBALS_ERROR */
|
||||||
gs->gs_xmlGenericError = xmlGenericErrorThrDef;
|
gs->gs_xmlGenericError = xmlGenericErrorThrDef;
|
||||||
gs->gs_xmlStructuredError = xmlStructuredErrorThrDef;
|
gs->gs_xmlStructuredError = xmlStructuredErrorThrDef;
|
||||||
gs->gs_xmlGenericErrorContext = xmlGenericErrorContextThrDef;
|
gs->gs_xmlGenericErrorContext = xmlGenericErrorContextThrDef;
|
||||||
gs->gs_xmlStructuredErrorContext = xmlStructuredErrorContextThrDef;
|
gs->gs_xmlStructuredErrorContext = xmlStructuredErrorContextThrDef;
|
||||||
|
|
||||||
|
/* XML_GLOBALS_TREE */
|
||||||
gs->gs_xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef;
|
gs->gs_xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef;
|
||||||
gs->gs_xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef;
|
gs->gs_xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef;
|
||||||
|
|
||||||
|
/* XML_GLOBALS_IO */
|
||||||
gs->gs_xmlParserInputBufferCreateFilenameValue =
|
gs->gs_xmlParserInputBufferCreateFilenameValue =
|
||||||
xmlParserInputBufferCreateFilenameValueThrDef;
|
xmlParserInputBufferCreateFilenameValueThrDef;
|
||||||
gs->gs_xmlOutputBufferCreateFilenameValue =
|
gs->gs_xmlOutputBufferCreateFilenameValue =
|
||||||
@@ -791,6 +816,10 @@ xmlNewGlobalState(int allowFailure)
|
|||||||
{
|
{
|
||||||
xmlGlobalState *gs;
|
xmlGlobalState *gs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use malloc/free to allow accessing globals before setting
|
||||||
|
* custom memory allocators.
|
||||||
|
*/
|
||||||
gs = malloc(sizeof(xmlGlobalState));
|
gs = malloc(sizeof(xmlGlobalState));
|
||||||
if (gs == NULL) {
|
if (gs == NULL) {
|
||||||
if (allowFailure)
|
if (allowFailure)
|
||||||
@@ -817,6 +846,8 @@ xmlGetThreadLocalStorage(int allowFailure) {
|
|||||||
|
|
||||||
(void) allowFailure;
|
(void) allowFailure;
|
||||||
|
|
||||||
|
xmlInitParser();
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
gs = &globalState;
|
gs = &globalState;
|
||||||
if (gs->initialized == 0)
|
if (gs->initialized == 0)
|
||||||
@@ -840,26 +871,20 @@ xmlGetThreadLocalStorage(int allowFailure) {
|
|||||||
|
|
||||||
#define XML_DEFINE_GLOBAL_WRAPPER(name, type, attrs) \
|
#define XML_DEFINE_GLOBAL_WRAPPER(name, type, attrs) \
|
||||||
type *__##name(void) { \
|
type *__##name(void) { \
|
||||||
if (IS_MAIN_THREAD) \
|
return (&xmlGetThreadLocalStorage(0)->gs_##name); \
|
||||||
return (&name); \
|
|
||||||
else \
|
|
||||||
return (&xmlGetThreadLocalStorage(0)->gs_##name); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XML_OP XML_DEFINE_GLOBAL_WRAPPER
|
#define XML_OP XML_DEFINE_GLOBAL_WRAPPER
|
||||||
XML_GLOBALS_ALLOC
|
XML_GLOBALS_ALLOC
|
||||||
XML_GLOBALS_ERROR
|
|
||||||
XML_GLOBALS_IO
|
|
||||||
XML_GLOBALS_PARSER
|
XML_GLOBALS_PARSER
|
||||||
|
XML_GLOBALS_ERROR
|
||||||
XML_GLOBALS_TREE
|
XML_GLOBALS_TREE
|
||||||
|
XML_GLOBALS_IO
|
||||||
#undef XML_OP
|
#undef XML_OP
|
||||||
|
|
||||||
const xmlError *
|
const xmlError *
|
||||||
__xmlLastError(void) {
|
__xmlLastError(void) {
|
||||||
if (IS_MAIN_THREAD)
|
return(&xmlGetThreadLocalStorage(0)->lastError);
|
||||||
return(&xmlLastError);
|
|
||||||
else
|
|
||||||
return(&xmlGetThreadLocalStorage(0)->lastError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -869,10 +894,7 @@ __xmlLastError(void) {
|
|||||||
*/
|
*/
|
||||||
unsigned *
|
unsigned *
|
||||||
xmlGetLocalRngState(void) {
|
xmlGetLocalRngState(void) {
|
||||||
if (IS_MAIN_THREAD)
|
return(xmlGetThreadLocalStorage(0)->localRngState);
|
||||||
return(xmlMainThreadRngState);
|
|
||||||
else
|
|
||||||
return(xmlGetThreadLocalStorage(0)->localRngState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For backward compatibility */
|
/* For backward compatibility */
|
||||||
@@ -938,7 +960,7 @@ __htmlDefaultSAXHandler(void) {
|
|||||||
int
|
int
|
||||||
xmlCheckThreadLocalStorage(void) {
|
xmlCheckThreadLocalStorage(void) {
|
||||||
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
|
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
|
||||||
if ((!xmlIsMainThreadInternal()) && (xmlGetThreadLocalStorage(1) == NULL))
|
if (xmlGetThreadLocalStorage(1) == NULL)
|
||||||
return(-1);
|
return(-1);
|
||||||
#endif
|
#endif
|
||||||
return(0);
|
return(0);
|
||||||
@@ -947,10 +969,7 @@ xmlCheckThreadLocalStorage(void) {
|
|||||||
xmlError *
|
xmlError *
|
||||||
xmlGetLastErrorInternal(void) {
|
xmlGetLastErrorInternal(void) {
|
||||||
#ifdef LIBXML_THREAD_ENABLED
|
#ifdef LIBXML_THREAD_ENABLED
|
||||||
if (IS_MAIN_THREAD)
|
return(&xmlGetThreadLocalStorage(0)->lastError);
|
||||||
return(&xmlLastError);
|
|
||||||
else
|
|
||||||
return(&xmlGetThreadLocalStorage(0)->lastError);
|
|
||||||
#else
|
#else
|
||||||
return(&xmlLastError);
|
return(&xmlLastError);
|
||||||
#endif
|
#endif
|
||||||
@@ -1012,6 +1031,10 @@ DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
|
|||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
if (xmlFree == free)
|
if (xmlFree == free)
|
||||||
xmlCleanupParser();
|
xmlCleanupParser();
|
||||||
|
if (globalkey != TLS_OUT_OF_INDEXES) {
|
||||||
|
TlsFree(globalkey);
|
||||||
|
globalkey = TLS_OUT_OF_INDEXES;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
37
threads.c
37
threads.c
@@ -427,8 +427,12 @@ xmlInitParserWinWrapper(INIT_ONCE *initOnce ATTRIBUTE_UNUSED,
|
|||||||
*
|
*
|
||||||
* Initialization function for the XML parser.
|
* Initialization function for the XML parser.
|
||||||
*
|
*
|
||||||
* Call once from the main thread before using the library in
|
* For older versions, it's recommended to call this function once
|
||||||
* multithreaded programs.
|
* from the main thread before using the library in multithreaded
|
||||||
|
* programs.
|
||||||
|
*
|
||||||
|
* Since 2.14.0, there's no distinction between threads. It should
|
||||||
|
* be unnecessary to call this function.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlInitParser(void) {
|
xmlInitParser(void) {
|
||||||
@@ -448,23 +452,29 @@ xmlInitParser(void) {
|
|||||||
* xmlCleanupParser:
|
* xmlCleanupParser:
|
||||||
*
|
*
|
||||||
* This function is named somewhat misleadingly. It does not clean up
|
* This function is named somewhat misleadingly. It does not clean up
|
||||||
* parser state but global memory allocated by the library itself. This
|
* parser state but global memory allocated by the library itself.
|
||||||
* 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 a process is multithreaded or uses other shared or
|
* Since 2.9.11, cleanup is performed automatically if a shared or
|
||||||
* dynamic libraries, calling this function may cause crashes if
|
* dynamic libxml2 library is unloaded. This function should only
|
||||||
* another thread or library is still using libxml2. It can be very
|
* be used to avoid false positives from memory leak checkers in
|
||||||
* hard to guess if libxml2 is in use by a process. In case of doubt
|
* static builds.
|
||||||
* abstain from calling this function.
|
*
|
||||||
|
* WARNING: xmlCleanupParser assumes that all other threads that called
|
||||||
|
* libxml2 functions have terminated. No library calls must be made
|
||||||
|
* after calling this function. In general, THIS FUNCTION SHOULD ONLY
|
||||||
|
* BE CALLED RIGHT BEFORE THE WHOLE PROCESS EXITS.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlCleanupParser(void) {
|
xmlCleanupParser(void) {
|
||||||
|
/*
|
||||||
|
* Unfortunately, some users call this function to fix memory
|
||||||
|
* leaks on unload with versions before 2.9.11. This can result
|
||||||
|
* in the library being reinitialized, so this use case must
|
||||||
|
* be supported.
|
||||||
|
*/
|
||||||
if (!xmlParserInitialized)
|
if (!xmlParserInitialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* These functions can call xmlFree. */
|
|
||||||
xmlCleanupCharEncodingHandlers();
|
xmlCleanupCharEncodingHandlers();
|
||||||
#ifdef LIBXML_CATALOG_ENABLED
|
#ifdef LIBXML_CATALOG_ENABLED
|
||||||
xmlCatalogCleanup();
|
xmlCatalogCleanup();
|
||||||
@@ -475,14 +485,13 @@ xmlCleanupParser(void) {
|
|||||||
xmlRelaxNGCleanupTypes();
|
xmlRelaxNGCleanupTypes();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These functions should never call xmlFree. */
|
|
||||||
xmlCleanupDictInternal();
|
xmlCleanupDictInternal();
|
||||||
xmlCleanupRandom();
|
xmlCleanupRandom();
|
||||||
xmlCleanupGlobalsInternal();
|
xmlCleanupGlobalsInternal();
|
||||||
xmlCleanupThreadsInternal();
|
xmlCleanupThreadsInternal();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must come last. xmlCleanupGlobalsInternal can call xmlFree which
|
* Must come after all cleanup functions that call xmlFree which
|
||||||
* uses xmlMemMutex in debug mode.
|
* uses xmlMemMutex in debug mode.
|
||||||
*/
|
*/
|
||||||
xmlCleanupMemoryInternal();
|
xmlCleanupMemoryInternal();
|
||||||
|
|||||||
Reference in New Issue
Block a user