diff --git a/globals.c b/globals.c index 1147e63f..ce689f50 100644 --- a/globals.c +++ b/globals.c @@ -806,6 +806,31 @@ xmlNewGlobalState(void) } #endif /* LIBXML_THREAD_ENABLED */ +/** + * xmlCheckThreadLocalStorage: + * + * Check whether thread-local storage could be allocated. + * + * In multithreaded environments, this function should be called once + * in each thread before calling other library functions to make sure + * that thread-local storage was allocated properly. + * + * Returns 0 on success or -1 if a memory allocation failed. A failed + * allocation signals a typically fatal and irrecoverable out-of-memory + * situation. Don't call any library functions in this case. + * + * This function never fails for the "main" thread which is the first + * thread calling xmlInitParser. + * + * Available since v2.12.0. + */ +int +xmlCheckThreadLocalStorage(void) { + if (IS_MAIN_THREAD) + return(0); + return((xmlGetGlobalState() == NULL) ? -1 : 0); +} + /** * xmlGetGlobalState: * diff --git a/include/libxml/globals.h b/include/libxml/globals.h index 1cc8477b..ddc9e9fe 100644 --- a/include/libxml/globals.h +++ b/include/libxml/globals.h @@ -82,6 +82,7 @@ typedef void (*xmlDeregisterNodeFunc) (xmlNodePtr node); typedef struct _xmlGlobalState xmlGlobalState; typedef xmlGlobalState *xmlGlobalStatePtr; +XMLPUBFUN int xmlCheckThreadLocalStorage(void); XML_DEPRECATED XMLPUBFUN void xmlInitializeGlobalState(xmlGlobalStatePtr gs); XML_DEPRECATED diff --git a/testThreads.c b/testThreads.c index d1535944..58b161bb 100644 --- a/testThreads.c +++ b/testThreads.c @@ -3,10 +3,11 @@ #include #include -#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) -#include -#include #include +#include +#include + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) #include #ifdef HAVE_PTHREAD_H #include @@ -57,6 +58,12 @@ thread_specific_data(void *private_data) const char *filename = params->filename; int okay = 1; + if (xmlCheckThreadLocalStorage() != 0) { + printf("xmlCheckThreadLocalStorage failed\n"); + params->okay = 0; + return(NULL); + } + if (!strcmp(filename, "test/threads/invalid.xml")) { xmlDoValidityCheckingDefaultValue = 0; xmlGenericErrorContext = stdout; @@ -98,17 +105,39 @@ thread_specific_data(void *private_data) return(NULL); } -#ifdef HAVE_PTHREAD_H +#ifdef _WIN32 +static DWORD WINAPI +win32_thread_specific_data(void *private_data) +{ + thread_specific_data(private_data); + return(0); +} +#endif +#endif /* LIBXML_THREADS_ENABLED */ + int main(void) { - unsigned int i, repeat; - int ret; + unsigned int repeat; + int status = 0; + + (void) repeat; xmlInitParser(); + + if (xmlCheckThreadLocalStorage() != 0) { + printf("xmlCheckThreadLocalStorage failed for main thread\n"); + return(1); + } + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) for (repeat = 0;repeat < TEST_REPEAT_COUNT;repeat++) { + unsigned int i; + int ret; + xmlLoadCatalog(catalog); +#ifdef HAVE_PTHREAD_H memset(tid, 0xff, sizeof(*tid)*num_threads); for (i = 0; i < num_threads; i++) { @@ -127,35 +156,7 @@ main(void) exit(1); } } - - xmlCatalogCleanup(); - for (i = 0; i < num_threads; i++) - if (threadParams[i].okay == 0) - printf("Thread %d handling %s failed\n", i, - threadParams[i].filename); - } - xmlCleanupParser(); - return (0); -} #elif defined(_WIN32) -static DWORD WINAPI -win32_thread_specific_data(void *private_data) -{ - thread_specific_data(private_data); - return(0); -} - -int -main(void) -{ - unsigned int i, repeat; - BOOL ret; - - xmlInitParser(); - for (repeat = 0;repeat < TEST_REPEAT_COUNT;repeat++) - { - xmlLoadCatalog(catalog); - for (i = 0; i < num_threads; i++) { tid[i] = (HANDLE) -1; @@ -187,26 +188,22 @@ main(void) } CloseHandle (tid[i]); } +#endif /* pthreads */ - xmlCatalogCleanup(); - for (i = 0; i < num_threads; i++) { - if (threadParams[i].okay == 0) - printf("Thread %d handling %s failed\n", i, - threadParams[i].filename); + xmlCatalogCleanup(); + + for (i = 0; i < num_threads; i++) { + if (threadParams[i].okay == 0) { + printf("Thread %d handling %s failed\n", i, + threadParams[i].filename); + status = 1; + } } } +#endif /* LIBXML_THREADS_ENABLED */ xmlCleanupParser(); - return (0); + return (status); } -#endif /* pthreads */ -#else /* !LIBXML_THREADS_ENABLED */ -int -main(void) -{ - fprintf(stderr, "libxml was not compiled with thread or catalog support\n"); - return (0); -} -#endif