From db0eb8df5a13ef5dcf228519682d41cfe5f8700b Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sun, 13 Jan 2002 13:35:00 +0000 Subject: [PATCH] applied Serguei Narojnyi's patch to add native thread support on the Win32 * threads.c: applied Serguei Narojnyi's patch to add native thread support on the Win32 platform * testThreadsWin32.c Makefile.am: added the test program also from Serguei, Win32 specific * include/win32config.h include/libxml/xmlwin32version.h.in: added patch from Igor for the Windows thread specific defines. Daniel --- ChangeLog | 9 ++ Makefile.am | 3 +- doc/Makefile.am | 2 +- include/libxml/xmlwin32version.h | 9 ++ include/libxml/xmlwin32version.h.in | 9 ++ include/win32config.h | 7 ++ testThreadsWin32.c | 146 ++++++++++++++++++++++++++++ threads.c | 104 +++++++++++++++++++- 8 files changed, 285 insertions(+), 4 deletions(-) create mode 100644 testThreadsWin32.c diff --git a/ChangeLog b/ChangeLog index 8f4d19e3..d08503da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Sun Jan 13 14:23:21 CET 2002 Daniel Veillard + + * threads.c: applied Serguei Narojnyi's patch to add native + thread support on the Win32 platform + * testThreadsWin32.c Makefile.am: added the test program also + from Serguei, Win32 specific + * include/win32config.h include/libxml/xmlwin32version.h.in: + added patch from Igor for the Windows thread specific defines. + Wed Jan 9 12:50:39 CET 2002 Daniel Veillard * entities.c: Anthony Jones pointed a bug in xmlCopyEntity() diff --git a/Makefile.am b/Makefile.am index 6f06df1b..6314acce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -569,7 +569,8 @@ EXTRA_DIST = xml2-config.in xml2Conf.sh.in libxml.spec.in libxml.spec \ example/Makefile.am example/gjobread.c example/gjobs.xml \ $(man_MANS) libxml-2.0.pc.in \ trionan.c trionan.h strio.c strio.h trio.c trio.h \ - triop.h triodef.h libxml.h + triop.h triodef.h libxml.h \ + testThreadsWin32.c pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libxml-2.0.pc diff --git a/doc/Makefile.am b/doc/Makefile.am index e5557ff6..95e03d9d 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -35,7 +35,7 @@ sgml: gtkdoc-mkdb --module=libxml --source-dir=$(DOC_SOURCE_DIR) html: - if ! test -d html ; then mkdir html ; fi + if test -n -d html ; then mkdir html ; fi -cd html && gtkdoc-mkhtml libxml ../$(DOC_MAIN_SGML_FILE) clean-local: diff --git a/include/libxml/xmlwin32version.h b/include/libxml/xmlwin32version.h index df11fed9..5ae4ee8b 100644 --- a/include/libxml/xmlwin32version.h +++ b/include/libxml/xmlwin32version.h @@ -67,6 +67,15 @@ extern void xmlCheckVersion(int version); #define WITHOUT_TRIO #endif +/** + * LIBXML_THREADS_ENABLED: + * + * Whether the thread support is configured in + */ +#if 0 +#define LIBXML_THREAD_ENABLED +#endif + /** * LIBXML_FTP_ENABLED: * diff --git a/include/libxml/xmlwin32version.h.in b/include/libxml/xmlwin32version.h.in index 41d5b140..614667ff 100644 --- a/include/libxml/xmlwin32version.h.in +++ b/include/libxml/xmlwin32version.h.in @@ -67,6 +67,15 @@ extern void xmlCheckVersion(int version); #define WITHOUT_TRIO #endif +/** + * LIBXML_THREADS_ENABLED: + * + * Whether the thread support is configured in + */ +#if 0 +#define LIBXML_THREAD_ENABLED +#endif + /** * LIBXML_FTP_ENABLED: * diff --git a/include/win32config.h b/include/win32config.h index 7b09d8ad..3e56217a 100644 --- a/include/win32config.h +++ b/include/win32config.h @@ -144,5 +144,12 @@ static int isnan (double d) { #define ATTRIBUTE_UNUSED #endif +/* Define this if you want to use Windows native thread implementation. + Undefine it if you wish to use another, pthreads for example. Note + that this alone does not enable threads, just specifies the + threading model. Threading support is activated in xmlversion.h by + defining LIBXML_THREAD_ENABLE. */ +#define HAVE_WIN32_THREADS + #endif /* __LIBXML_WIN32_CONFIG__ */ diff --git a/testThreadsWin32.c b/testThreadsWin32.c new file mode 100644 index 00000000..111e007f --- /dev/null +++ b/testThreadsWin32.c @@ -0,0 +1,146 @@ +#include +#include +#include "libxml.h" + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +#include +#include +#include +#include +#include +#include +#include + +#define MAX_ARGC 20 +#define TEST_REPEAT_COUNT 500 + +static HANDLE tid[MAX_ARGC]; + +static const char *catalog = "test/threads/complex.xml"; +static char *testfiles[] = { + "test/threads/abc.xml", + "test/threads/acb.xml", + "test/threads/bac.xml", + "test/threads/bca.xml", + "test/threads/cab.xml", + "test/threads/cba.xml", + "test/threads/invalid.xml", +}; + +const char *Okay = "OK"; +const char *Failed = "Failed"; + +#ifndef xmlDoValidityCheckingDefaultValue +#error xmlDoValidityCheckingDefaultValue is not a macro +#endif +#ifndef xmlGenericErrorContext +#error xmlGenericErrorContext is not a macro +#endif + +static DWORD WINAPI +thread_specific_data(void *private_data) +{ + xmlDocPtr myDoc; + const char *filename = (const char *) private_data; + int okay = 1; + + if (!strcmp(filename, "test/threads/invalid.xml")) { + xmlDoValidityCheckingDefaultValue = 0; + xmlGenericErrorContext = stdout; + } else { + xmlDoValidityCheckingDefaultValue = 1; + xmlGenericErrorContext = stderr; + } + myDoc = xmlParseFile(filename); + if (myDoc) { + xmlFreeDoc(myDoc); + } else { + printf("parse failed\n"); + okay = 0; + } + if (!strcmp(filename, "test/threads/invalid.xml")) { + if (xmlDoValidityCheckingDefaultValue != 0) { + printf("ValidityCheckingDefaultValue override failed\n"); + okay = 0; + } + if (xmlGenericErrorContext != stdout) { + printf("xmlGenericErrorContext override failed\n"); + okay = 0; + } + } else { + if (xmlDoValidityCheckingDefaultValue != 1) { + printf("ValidityCheckingDefaultValue override failed\n"); + okay = 0; + } + if (xmlGenericErrorContext != stderr) { + printf("xmlGenericErrorContext override failed\n"); + okay = 0; + } + } + if (okay == 0) + return ((DWORD) Failed); + return ((DWORD) Okay); +} + +int +main() +{ + unsigned int i, repeat; + unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); + DWORD results[MAX_ARGC]; + BOOL ret; + + xmlInitParser(); + for (repeat = 0;repeat < TEST_REPEAT_COUNT;repeat++) + { + xmlLoadCatalog(catalog); + + for (i = 0; i < num_threads; i++) + { + results[i] = 0; + tid[i] = (HANDLE) -1; + } + + for (i = 0; i < num_threads; i++) + { + DWORD useless; + tid[i] = CreateThread (NULL, 0, thread_specific_data, testfiles[i], 0, &useless); + if (tid[i] == NULL) + { + perror("CreateThread"); + exit(1); + } + } + + if (WaitForMultipleObjects (num_threads, tid, TRUE, INFINITE) == WAIT_FAILED) perror ("WaitForMultipleObjects failed"); + + for (i = 0; i < num_threads; i++) + { + ret = GetExitCodeThread (tid[i], &results[i]); + if (ret == 0) + { + perror("GetExitCodeThread"); + exit(1); + } + CloseHandle (tid[i]); + } + + xmlCatalogCleanup(); + for (i = 0; i < num_threads; i++) + if (results[i] != (DWORD) Okay) printf("Thread %d handling %s failed\n", i, testfiles[i]); + } + + xmlCleanupParser(); + xmlMemoryDump(); + + return (0); +} + +#else /* !LIBXML_THREADS_ENABLED */ +int +main() +{ + fprintf(stderr, "libxml was not compiled with thread or catalog support\n"); + return (0); +} +#endif diff --git a/threads.c b/threads.c index be3b1316..dc69f471 100644 --- a/threads.c +++ b/threads.c @@ -26,6 +26,12 @@ #ifdef HAVE_PTHREAD_H #include #endif +#ifdef HAVE_WIN32_THREADS +#include +#ifndef _MSC_VER +#include +#endif +#endif #if defined(SOLARIS) #include @@ -45,6 +51,8 @@ struct _xmlMutex { #ifdef HAVE_PTHREAD_H pthread_mutex_t lock; +#elif defined HAVE_WIN32_THREADS + HANDLE mutex; #else int empty; #endif @@ -60,6 +68,9 @@ struct _xmlRMutex { unsigned int waiters; pthread_t tid; pthread_cond_t cv; +#elif defined HAVE_WIN32_THREADS + CRITICAL_SECTION cs; + unsigned int count; #else int empty; #endif @@ -74,7 +85,16 @@ struct _xmlRMutex { static pthread_key_t globalkey; static pthread_t mainthread; static pthread_once_t once_control = PTHREAD_ONCE_INIT; -#endif +#elif defined HAVE_WIN32_THREADS +#ifdef _MSC_VER +static __declspec (thread) xmlGlobalState tlstate; +static __declspec (thread) int tlstate_inited = 0; +#else +static DWORD globalkey; +#endif /* _MSC_VER */ +static DWORD mainthread; +static int run_once_init = 1; +#endif /* HAVE_WIN32_THREADS */ static xmlRMutexPtr xmlLibraryLock = NULL; static void xmlOnceInit(void); @@ -95,6 +115,8 @@ xmlNewMutex(void) return (NULL); #ifdef HAVE_PTHREAD_H pthread_mutex_init(&tok->lock, NULL); +#elif defined HAVE_WIN32_THREADS + tok->mutex = CreateMutex (NULL, FALSE, NULL); #endif return (tok); } @@ -111,6 +133,8 @@ xmlFreeMutex(xmlMutexPtr tok) { #ifdef HAVE_PTHREAD_H pthread_mutex_destroy(&tok->lock); +#elif defined HAVE_WIN32_THREADS + CloseHandle (tok->mutex); #endif free(tok); } @@ -126,6 +150,8 @@ xmlMutexLock(xmlMutexPtr tok) { #ifdef HAVE_PTHREAD_H pthread_mutex_lock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + WaitForSingleObject (tok->mutex, INFINITE); #endif } @@ -141,6 +167,8 @@ xmlMutexUnlock(xmlMutexPtr tok) { #ifdef HAVE_PTHREAD_H pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + ReleaseMutex (tok->mutex); #endif } @@ -165,6 +193,9 @@ xmlNewRMutex(void) pthread_mutex_init(&tok->lock, NULL); tok->held = 0; tok->waiters = 0; +#elif defined HAVE_WIN32_THREADS + InitializeCriticalSection (&tok->cs); + tok->count = 0; #endif return (tok); } @@ -181,6 +212,8 @@ xmlFreeRMutex(xmlRMutexPtr tok) { #ifdef HAVE_PTHREAD_H pthread_mutex_destroy(&tok->lock); +#elif defined HAVE_WIN32_THREADS + DeleteCriticalSection (&tok->cs); #endif free(tok); } @@ -211,6 +244,9 @@ xmlRMutexLock(xmlRMutexPtr tok) tok->tid = pthread_self(); tok->held = 1; pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + EnterCriticalSection (&tok->cs); + ++tok->count; #endif } @@ -232,6 +268,8 @@ xmlRMutexUnlock(xmlRMutexPtr tok) tok->tid = 0; } pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + if (!--tok->count) LeaveCriticalSection (&tok->cs); #endif } @@ -242,6 +280,7 @@ xmlRMutexUnlock(xmlRMutexPtr tok) ************************************************************************/ #ifdef LIBXML_THREAD_ENABLED +#ifndef _MSC_VER /** * xmlFreeGlobalState: * @state: a thread global state @@ -277,6 +316,7 @@ xmlNewGlobalState(void) xmlInitializeGlobalState(gs); return (gs); } +#endif /* _MSC_VER */ #endif /* LIBXML_THREAD_ENABLED */ @@ -287,6 +327,27 @@ xmlNewGlobalState(void) * * Returns the thread global state or NULL in case of error */ + +#ifdef HAVE_WIN32_THREADS +#ifndef _MSC_VER +typedef struct _xmlGlobalStateCleanupHelperParams +{ + HANDLE thread; + void *memory; +} xmlGlobalStateCleanupHelperParams; + +void __cdecl xmlGlobalStateCleanupHelper (void *p) +{ + xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p; + WaitForSingleObject (params->thread, INFINITE); + CloseHandle (params->thread); + xmlFreeGlobalState (params->memory); + free (params); + _endthread (); +} +#endif /* _MSC_VER */ +#endif /* HAVE_WIN32_THREADS */ + xmlGlobalStatePtr xmlGetGlobalState(void) { @@ -303,12 +364,40 @@ xmlGetGlobalState(void) return (tsd); } return (globalval); +#elif defined HAVE_WIN32_THREADS +#ifdef _MSC_VER + if (!tlstate_inited) + { + tlstate_inited = 1; + xmlInitializeGlobalState (&tlstate); + } + + return &tlstate; +#else /* !_MSC_VER */ + xmlGlobalState *globalval; + + if (run_once_init) { run_once_init = 0; xmlOnceInit (); } + + if ((globalval = (xmlGlobalState *) TlsGetValue (globalkey)) == NULL) + { + xmlGlobalState *tsd = xmlNewGlobalState(); + xmlGlobalStateCleanupHelperParams *p = (xmlGlobalStateCleanupHelperParams *) malloc (sizeof (xmlGlobalStateCleanupHelperParams)); + + p->memory = tsd; + DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS); + + TlsSetValue (globalkey, tsd); + _beginthread (xmlGlobalStateCleanupHelper, 0, p); + + return (tsd); + } + return (globalval); +#endif /* _MSC_VER */ #else return(NULL); #endif } - /************************************************************************ * * * Library wide thread interfaces * @@ -327,6 +416,8 @@ xmlGetThreadId(void) { #ifdef HAVE_PTHREAD_H return((int) pthread_self()); +#elif defined HAVE_WIN32_THREADS + return GetCurrentThreadId (); #else return((int) 0); #endif @@ -344,6 +435,8 @@ xmlIsMainThread(void) { #ifdef HAVE_PTHREAD_H pthread_once(&once_control, xmlOnceInit); +#elif defined HAVE_WIN32_THREADS + if (run_once_init) { run_once_init = 0; xmlOnceInit (); } #endif #ifdef DEBUG_THREADS @@ -351,6 +444,8 @@ xmlIsMainThread(void) #endif #ifdef HAVE_PTHREAD_H return(mainthread == pthread_self()); +#elif defined HAVE_WIN32_THREADS + return (mainthread == GetCurrentThreadId ()); #else return(1); #endif @@ -428,5 +523,10 @@ xmlOnceInit(void) { #ifdef HAVE_PTHREAD_H (void) pthread_key_create(&globalkey, xmlFreeGlobalState); mainthread = pthread_self(); +#elif defined HAVE_WIN32_THREADS +#ifndef _MSC_VER + globalkey = TlsAlloc (); +#endif /* _MSC_VER */ + mainthread = GetCurrentThreadId (); #endif }