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
This commit is contained in:
Daniel Veillard 2002-01-13 13:35:00 +00:00
parent 845cce4cf1
commit db0eb8df5a
8 changed files with 285 additions and 4 deletions

View File

@ -1,3 +1,12 @@
Sun Jan 13 14:23:21 CET 2002 Daniel Veillard <daniel@veillard.com>
* 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 <daniel@veillard.com>
* entities.c: Anthony Jones pointed a bug in xmlCopyEntity()

View File

@ -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

View File

@ -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:

View File

@ -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:
*

View File

@ -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:
*

View File

@ -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__ */

146
testThreadsWin32.c Normal file
View File

@ -0,0 +1,146 @@
#include <stdlib.h>
#include <stdio.h>
#include "libxml.h"
#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
#include <libxml/globals.h>
#include <libxml/threads.h>
#include <libxml/parser.h>
#include <libxml/catalog.h>
#include <windows.h>
#include <string.h>
#include <assert.h>
#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

104
threads.c
View File

@ -26,6 +26,12 @@
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
#ifndef _MSC_VER
#include <process.h>
#endif
#endif
#if defined(SOLARIS)
#include <note.h>
@ -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
}