From b847864fc2f7151c81e57d02ca3b523dc5d8cf72 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 12 Oct 2001 17:29:10 +0000 Subject: [PATCH] started integrating the core of the thread support not activated yet but * Makefile.am include/libxml/Makefile.am include/libxml/globals.h globals.c include/libxml/threads.h threads.c build_glob.py global.data xmlcatalog.c acconfig.h configure.in: started integrating the core of the thread support not activated yet but half integrated. The code should still compile and work anyway. Daniel --- ChangeLog | 9 + Makefile.am | 8 +- acconfig.h | 2 + build_glob.py | 107 +++++++ config.h.in | 5 + configure.in | 26 +- global.data | 27 ++ globals.c | 498 +++++++++++++++++++++++++++++++++ include/libxml/Makefile.am | 3 +- include/libxml/globals.h | 294 +++++++++++++++++++ include/libxml/threads.h | 54 ++++ include/libxml/xmlversion.h.in | 11 + threads.c | 372 ++++++++++++++++++++++++ xmlcatalog.c | 2 + 14 files changed, 1411 insertions(+), 7 deletions(-) create mode 100755 build_glob.py create mode 100644 global.data create mode 100644 globals.c create mode 100644 include/libxml/globals.h create mode 100644 include/libxml/threads.h create mode 100644 threads.c diff --git a/ChangeLog b/ChangeLog index b73c0f8b..5a7268b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Fri Oct 12 19:25:55 CEST 2001 Daniel Veillard + + * Makefile.am include/libxml/Makefile.am + include/libxml/globals.h globals.c include/libxml/threads.h + threads.c build_glob.py global.data xmlcatalog.c acconfig.h + configure.in: started integrating the core of the thread support + not activated yet but half integrated. The code should still + compile and work anyway. + Fri Oct 12 00:53:03 CEST 2001 Daniel Veillard * HTMLtree.c catalog.c debugXML.c entities.c nanoftp.c diff --git a/Makefile.am b/Makefile.am index f52516d3..89de4b81 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS=no-dependencies SUBDIRS = include . doc example -INCLUDES = -I@srcdir@/include -I$(top_builddir)/include @Z_CFLAGS@ +INCLUDES = -I@srcdir@/include -I$(top_builddir)/include @THREAD_CFLAGS@ @Z_CFLAGS@ noinst_PROGRAMS=testSAX testHTML testXPath testURI testDocbook @@ -23,19 +23,19 @@ libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c \ valid.c xlink.c HTMLparser.c HTMLtree.c debugXML.c xpath.c \ xpointer.c xinclude.c nanohttp.c nanoftp.c DOCBparser.c \ - catalog.c strio.c trio.c + catalog.c threads.c strio.c trio.c else libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c \ valid.c xlink.c HTMLparser.c HTMLtree.c debugXML.c xpath.c \ xpointer.c xinclude.c nanohttp.c nanoftp.c DOCBparser.c \ - catalog.c + catalog.c threads.c endif DEPS = $(top_builddir)/libxml2.la -LDADDS = $(top_builddir)/libxml2.la @Z_LIBS@ $(ICONV_LIBS) -lm +LDADDS = $(top_builddir)/libxml2.la @THREAD_LIBS@ @Z_LIBS@ $(ICONV_LIBS) -lm man_MANS = xmllint.1 xml2-config.1 libxml.4 diff --git a/acconfig.h b/acconfig.h index e29c0f95..5a2d3a08 100644 --- a/acconfig.h +++ b/acconfig.h @@ -7,3 +7,5 @@ #undef HAVE_LIBHISTORY #undef HAVE_LIBREADLINE #undef SOCKLEN_T +#undef HAVE_LIBPTHREAD +#undef HAVE_PTHREAD_H diff --git a/build_glob.py b/build_glob.py new file mode 100755 index 00000000..fbf45c14 --- /dev/null +++ b/build_glob.py @@ -0,0 +1,107 @@ +#! /usr/bin/env python +### +# +# build_glob.py : Build the global_functions.h and global_functions.c +# files which are required to implement the user +# interface to global variables now that thread specific +# data (TSD) is used to emulate global state. +# +# See Copyright for the status of this software. +# Gary.Pennington@sun.com +### +import os, string + +class globvar: + def __init__(self, type, name): + self.type=type + self.name=name + +def writeline(file, line=None): + if line: + file.write(line) + file.write(os.linesep) + +if __name__ == "__main__": + globals={} + global_data=open("global.data").readlines() + global_code=open("globals.c").readlines() + global_hdr=open("include/libxml/globals.h").readlines() + global_functions_hdr=open("include/libxml/globals.h", "w+") + global_functions_impl=open("globals.c", "w+") + + # + # Rebuild the beginning of the file up to the + # Automatically generated string + # + for line in global_hdr: + if line[-len(os.linesep):] == os.linesep: + line = line[:-len(os.linesep)] + if line == " * Automatically generated by build_glob.py.": + break + writeline(global_functions_hdr, line) + + writeline(global_functions_hdr, " * Automatically generated by build_glob.py.") + writeline(global_functions_hdr, " * Do not modify the previous line.") + writeline(global_functions_hdr, " */") + writeline(global_functions_hdr) + + for line in global_code: + if line[-len(os.linesep):] == os.linesep: + line = line[:-len(os.linesep)] + if line == " * Automatically generated by build_glob.py.": + break + writeline(global_functions_impl, line) + + writeline(global_functions_impl, " * Automatically generated by build_glob.py.") + writeline(global_functions_impl, " * Do not modify the previous line.") + writeline(global_functions_impl, " */") + writeline(global_functions_impl) + + # Now process the data and write it to the appropriate output file + for line in global_data: + if line[0]=='#': + continue + if line[-len(os.linesep):] == os.linesep: + line = line[:-len(os.linesep)] + fields = string.split(line, ",") + # Update the header file + writeline(global_functions_hdr) + writeline(global_functions_hdr, "#ifdef LIBXML_THREAD_ENABLED") + global_functions_hdr.write("extern "+fields[0]+" *") + if len(fields) == 3: + global_functions_hdr.write("(*") + global_functions_hdr.write("__"+fields[1]+"(void)") + if len(fields) == 3: + global_functions_hdr.write(")"+fields[2]) + writeline(global_functions_hdr,";") + writeline(global_functions_hdr,"#define "+fields[1]+" \\") + writeline(global_functions_hdr,"(*(__"+fields[1]+"()))") + writeline(global_functions_hdr,"#else") + if len(fields) == 3: + writeline(global_functions_hdr,"extern "+fields[0]+" "+fields[1]+fields[2]+";") + else: + writeline(global_functions_hdr,"extern "+fields[0]+" "+fields[1]+";") + writeline(global_functions_hdr,"#endif") + # Update the implementation file + writeline(global_functions_impl) + writeline(global_functions_impl, "extern "+fields[0]+" "+fields[1]+";") + writeline(global_functions_impl, "#undef\t"+fields[1]) + writeline(global_functions_impl, fields[0]+" *") + if len(fields) == 3: + global_functions_impl.write("(*") + global_functions_impl.write("__"+fields[1]+"(void)") + if len(fields) == 3: + writeline(global_functions_impl, ")[]") + writeline(global_functions_impl, " {") + writeline(global_functions_impl, " if (IS_MAIN_THREAD)") + writeline(global_functions_impl, "\treturn (&"+fields[1]+");") + writeline(global_functions_impl, " else") + writeline(global_functions_impl, "\treturn (&get_glob_struct()->"+fields[1]+");") + writeline(global_functions_impl, "}") + # Terminate the header file with appropriate boilerplate + writeline(global_functions_hdr) + writeline(global_functions_hdr, "#ifdef __cplusplus") + writeline(global_functions_hdr, "}") + writeline(global_functions_hdr, "#endif") + writeline(global_functions_hdr) + writeline(global_functions_hdr, "#endif /* __XML_GLOBALS_H */") diff --git a/config.h.in b/config.h.in index bf54bc04..83971e4d 100644 --- a/config.h.in +++ b/config.h.in @@ -15,6 +15,8 @@ #undef HAVE_LIBHISTORY #undef HAVE_LIBREADLINE #undef SOCKLEN_T +#undef HAVE_LIBPTHREAD +#undef HAVE_PTHREAD_H /* Define if you have the _stat function. */ #undef HAVE__STAT @@ -91,6 +93,9 @@ /* Define if you have the header file. */ #undef HAVE_DIRENT_H +/* Define if you have the header file. */ +#undef HAVE_DLFCN_H + /* Define if you have the header file. */ #undef HAVE_ERRNO_H diff --git a/configure.in b/configure.in index baed6df6..9f50db73 100644 --- a/configure.in +++ b/configure.in @@ -243,10 +243,32 @@ AM_CONDITIONAL(WITH_TRIO_SOURCES, test "${NEED_TRIO}" = "1") AC_SUBST(WITH_TRIO) dnl -dnl Aloow to disable various pieces +dnl Aloow to enable/disable various pieces dnl -AC_ARG_WITH(history, [ --with-history Add history support to xmllint shell(off)]) +THREAD_LIBS="" +WITH_THREADS=0 +THREAD_CFLAGS="" +AC_ARG_WITH(threads, [ --with-threads Add multithread support(off)]) +if test "$with_threads" = "yes" ; then + echo Enabling multithreaded support + + AC_CHECK_HEADER(pthread.h, + AC_CHECK_LIB(pthread, pthread_mutex_lock,[ + THREAD_LIBS="-lpthread" + AC_DEFINE(HAVE_LIBPTHREAD) + AC_DEFINE(HAVE_PTHREAD_H) + WITH_THREADS=1])) + + if test "$WITH_THREADS" = "1" ; then + THREAD_CFLAGS="$XML_CFLAGS -D_REENTRANT" + fi +fi +AC_SUBST(THREAD_LIBS) +AC_SUBST(WITH_THREADS) +AC_SUBST(THREAD_CFLAGS) + +AC_ARG_WITH(history, [ --with-history Add history support to xmllint shell(off)]) if test "$with_history" = "yes" ; then echo Enabling xmllint shell history dnl check for terminal library. this is a very cool solution diff --git a/global.data b/global.data new file mode 100644 index 00000000..45c3b31e --- /dev/null +++ b/global.data @@ -0,0 +1,27 @@ +xmlSAXHandler,docbDefaultSAXHandler +xmlSAXHandler,htmlDefaultSAXHandler +int,oldXMLWDcompatibility +xmlBufferAllocationScheme,xmlBufferAllocScheme +int,xmlDefaultBufferSize +xmlSAXHandler,xmlDefaultSAXHandler +xmlSAXLocator,xmlDefaultSAXLocator +int,xmlDoValidityCheckingDefaultValue +xmlFreeFunc,xmlFree +xmlGenericErrorFunc,xmlGenericError +void *,xmlGenericErrorContext +int,xmlGetWarningsDefaultValue +int,xmlIndentTreeOutput +int,xmlKeepBlanksDefaultValue +int,xmlLineNumbersDefaultValue +int,xmlLoadExtDtdDefaultValue +xmlMallocFunc,xmlMalloc +xmlStrdupFunc,xmlMemStrdup +int,xmlParserDebugEntities +const char *,xmlParserVersion +int,xmlPedanticParserDefaultValue +xmlReallocFunc,xmlRealloc +int,xmlSaveNoEmptyTags +#const xmlChar,xmlStringComment,[] +#const xmlChar,xmlStringText,[] +#const xmlChar,xmlStringTextNoenc,[] +int,xmlSubstituteEntitiesDefaultValue \ No newline at end of file diff --git a/globals.c b/globals.c new file mode 100644 index 00000000..c509287b --- /dev/null +++ b/globals.c @@ -0,0 +1,498 @@ +/* + * globals.c: definition and handling of the set of global variables + * of the library + * + * The bottom of this file is automatically generated by build_glob.py + * based on the description file global.data + * + * See Copyright for the status of this software. + * + * Gary Pennington + * daniel@veillard.com + */ + +#include "libxml.h" + +#include +#include + +/* + * Helpful Macro + */ +#ifdef WITH_PTHREAD_H +#if defined(SOLARIS) +#define THR_MAIN(tid) (-1 == thr_main() || tid == thr_main()) +#else +#define THR_MAIN(tid) (tid == 0 || tid == 1024) +#endif + +#define IS_MAIN_THREAD (THR_MAIN(pthread_self())) +#else +#define IS_MAIN_THREAD 1 +#endif + +/************************************************************************ + * * + * All the user accessible global variables of the library * + * * + ************************************************************************/ + +const char *xmlParserVersion = LIBXML_VERSION_STRING; +/* + * Memory allocation routines + */ +#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY) +xmlFreeFunc xmlFree = (xmlFreeFunc) xmlMemFree; +xmlMallocFunc xmlMalloc = (xmlMallocFunc) xmlMemMalloc; +xmlReallocFunc xmlRealloc = (xmlReallocFunc) xmlMemRealloc; +xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup; +#else +xmlFreeFunc xmlFree = (xmlFreeFunc) free; +xmlMallocFunc xmlMalloc = (xmlMallocFunc) malloc; +xmlReallocFunc xmlRealloc = (xmlReallocFunc) realloc; +xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) strdup; +#endif + +/* + * Buffers stuff + */ +xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; +int xmlDefaultBufferSize = BASE_BUFFER_SIZE; + +/* + * Parser defaults + */ +int oldXMLWDcompatibility = 0; /* DEPRECATED */ +int xmlParserDebugEntities = 0; +int xmlDoValidityCheckingDefaultValue = 0; +int xmlGetWarningsDefaultValue = 1; +int xmlLoadExtDtdDefaultValue = 0; +int xmlPedanticParserDefaultValue = 0; +int xmlLineNumbersDefaultValue = 0; +int xmlKeepBlanksDefaultValue = 1; +int xmlSubstituteEntitiesDefaultValue = 0; + +/* + * Error handling + */ + +/* xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc; */ +/* Must initialize xmlGenericError in xmlInitParser */ +xmlGenericErrorFunc xmlGenericError; +void *xmlGenericErrorContext = NULL; + +/* + * output defaults + */ +int xmlIndentTreeOutput = 0; +int xmlSaveNoEmptyTags = 0; + +/* + * Default handler for XML, builds the DOM tree + */ +xmlSAXHandler xmlDefaultSAXHandler = { + internalSubset, + isStandalone, + hasInternalSubset, + hasExternalSubset, + resolveEntity, + getEntity, + entityDecl, + notationDecl, + attributeDecl, + elementDecl, + unparsedEntityDecl, + setDocumentLocator, + startDocument, + endDocument, + startElement, + endElement, + reference, + characters, + characters, + processingInstruction, + comment, + xmlParserWarning, + xmlParserError, + xmlParserError, + getParameterEntity, + cdataBlock, + externalSubset, + 0 +}; + +/* + * The default SAX Locator. + */ + +xmlSAXLocator xmlDefaultSAXLocator = { + getPublicId, getSystemId, getLineNumber, getColumnNumber +}; + +#ifdef LIBXML_HTML_ENABLED +/* + * Default handler for HTML, builds the DOM tree + */ +xmlSAXHandler htmlDefaultSAXHandler = { + internalSubset, + NULL, + NULL, + NULL, + NULL, + getEntity, + NULL, + NULL, + NULL, + NULL, + NULL, + setDocumentLocator, + startDocument, + endDocument, + startElement, + endElement, + NULL, + characters, + ignorableWhitespace, + NULL, + comment, + xmlParserWarning, + xmlParserError, + xmlParserError, + getParameterEntity, + cdataBlock, + NULL, + 0 +}; +#endif /* LIBXML_HTML_ENABLED */ + +#ifdef LIBXML_DOCB_ENABLED +/* + * Default handler for SGML DocBook, builds the DOM tree + */ +xmlSAXHandler docbDefaultSAXHandler = { + internalSubset, + isStandalone, + hasInternalSubset, + hasExternalSubset, + resolveEntity, + getEntity, + entityDecl, + NULL, + NULL, + NULL, + NULL, + setDocumentLocator, + startDocument, + endDocument, + startElement, + endElement, + reference, + characters, + ignorableWhitespace, + NULL, + comment, + xmlParserWarning, + xmlParserError, + xmlParserError, + getParameterEntity, + NULL, + NULL, + 0 +}; +#endif /* LIBXML_DOCB_ENABLED */ + +/** + * xmlInitializeGlobalState: + * @gs: a pointer to a newly allocated global state + * + * xmlInitializeGlobalState() initialize a global state with all the + * default values of the library. + */ +void +xmlInitializeGlobalState(xmlGlobalStatePtr gs) +{ + /* + * Perform initialisation as required by libxml + */ + initdocbDefaultSAXHandler(&gs->docbDefaultSAXHandler); + inithtmlDefaultSAXHandler(&gs->htmlDefaultSAXHandler); + gs->oldXMLWDcompatibility = 0; + gs->xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; + gs->xmlDefaultBufferSize = BASE_BUFFER_SIZE; + initxmlDefaultSAXHandler(&gs->xmlDefaultSAXHandler, 1); + gs->xmlDefaultSAXLocator.getPublicId = getPublicId; + gs->xmlDefaultSAXLocator.getSystemId = getSystemId; + gs->xmlDefaultSAXLocator.getLineNumber = getLineNumber; + gs->xmlDefaultSAXLocator.getColumnNumber = getColumnNumber; + gs->xmlDoValidityCheckingDefaultValue = 0; +#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY) + gs->xmlFree = (xmlFreeFunc) xmlMemFree; + gs->xmlMalloc = (xmlMallocFunc) xmlMemMalloc; + gs->xmlRealloc = (xmlReallocFunc) xmlMemRealloc; + gs->xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup; +#else + gs->xmlFree = (xmlFreeFunc) free; + gs->xmlMalloc = (xmlMallocFunc) malloc; + gs->xmlRealloc = (xmlReallocFunc) realloc; + gs->xmlMemStrdup = (xmlStrdupFunc) strdup; +#endif + initGenericErrorDefaultFunc(&gs->xmlGenericError); + gs->xmlGenericErrorContext = NULL; + gs->xmlGetWarningsDefaultValue = 1; + gs->xmlIndentTreeOutput = 0; + gs->xmlKeepBlanksDefaultValue = 1; + gs->xmlLineNumbersDefaultValue = 0; + gs->xmlLoadExtDtdDefaultValue = 0; + gs->xmlParserDebugEntities = 0; + gs->xmlParserVersion = LIBXML_VERSION_STRING; + gs->xmlPedanticParserDefaultValue = 0; + gs->xmlSaveNoEmptyTags = 0; + gs->xmlSubstituteEntitiesDefaultValue = 0; +} + +/* + * Everything starting from the line below is + * Automatically generated by build_glob.py. + * Do not modify the previous line. + */ + + +extern xmlSAXHandler docbDefaultSAXHandler; +#undef docbDefaultSAXHandler +xmlSAXHandler * +__docbDefaultSAXHandler(void) { + if (IS_MAIN_THREAD) + return (&docbDefaultSAXHandler); + else + return (&get_glob_struct()->docbDefaultSAXHandler); +} + +extern xmlSAXHandler htmlDefaultSAXHandler; +#undef htmlDefaultSAXHandler +xmlSAXHandler * +__htmlDefaultSAXHandler(void) { + if (IS_MAIN_THREAD) + return (&htmlDefaultSAXHandler); + else + return (&get_glob_struct()->htmlDefaultSAXHandler); +} + +extern int oldXMLWDcompatibility; +#undef oldXMLWDcompatibility +int * +__oldXMLWDcompatibility(void) { + if (IS_MAIN_THREAD) + return (&oldXMLWDcompatibility); + else + return (&get_glob_struct()->oldXMLWDcompatibility); +} + +extern xmlBufferAllocationScheme xmlBufferAllocScheme; +#undef xmlBufferAllocScheme +xmlBufferAllocationScheme * +__xmlBufferAllocScheme(void) { + if (IS_MAIN_THREAD) + return (&xmlBufferAllocScheme); + else + return (&get_glob_struct()->xmlBufferAllocScheme); +} + +extern int xmlDefaultBufferSize; +#undef xmlDefaultBufferSize +int * +__xmlDefaultBufferSize(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultBufferSize); + else + return (&get_glob_struct()->xmlDefaultBufferSize); +} + +extern xmlSAXHandler xmlDefaultSAXHandler; +#undef xmlDefaultSAXHandler +xmlSAXHandler * +__xmlDefaultSAXHandler(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultSAXHandler); + else + return (&get_glob_struct()->xmlDefaultSAXHandler); +} + +extern xmlSAXLocator xmlDefaultSAXLocator; +#undef xmlDefaultSAXLocator +xmlSAXLocator * +__xmlDefaultSAXLocator(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultSAXLocator); + else + return (&get_glob_struct()->xmlDefaultSAXLocator); +} + +extern int xmlDoValidityCheckingDefaultValue; +#undef xmlDoValidityCheckingDefaultValue +int * +__xmlDoValidityCheckingDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlDoValidityCheckingDefaultValue); + else + return (&get_glob_struct()->xmlDoValidityCheckingDefaultValue); +} + +extern xmlFreeFunc xmlFree; +#undef xmlFree +xmlFreeFunc * +__xmlFree(void) { + if (IS_MAIN_THREAD) + return (&xmlFree); + else + return (&get_glob_struct()->xmlFree); +} + +extern xmlGenericErrorFunc xmlGenericError; +#undef xmlGenericError +xmlGenericErrorFunc * +__xmlGenericError(void) { + if (IS_MAIN_THREAD) + return (&xmlGenericError); + else + return (&get_glob_struct()->xmlGenericError); +} + +extern void * xmlGenericErrorContext; +#undef xmlGenericErrorContext +void * * +__xmlGenericErrorContext(void) { + if (IS_MAIN_THREAD) + return (&xmlGenericErrorContext); + else + return (&get_glob_struct()->xmlGenericErrorContext); +} + +extern int xmlGetWarningsDefaultValue; +#undef xmlGetWarningsDefaultValue +int * +__xmlGetWarningsDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlGetWarningsDefaultValue); + else + return (&get_glob_struct()->xmlGetWarningsDefaultValue); +} + +extern int xmlIndentTreeOutput; +#undef xmlIndentTreeOutput +int * +__xmlIndentTreeOutput(void) { + if (IS_MAIN_THREAD) + return (&xmlIndentTreeOutput); + else + return (&get_glob_struct()->xmlIndentTreeOutput); +} + +extern int xmlKeepBlanksDefaultValue; +#undef xmlKeepBlanksDefaultValue +int * +__xmlKeepBlanksDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlKeepBlanksDefaultValue); + else + return (&get_glob_struct()->xmlKeepBlanksDefaultValue); +} + +extern int xmlLineNumbersDefaultValue; +#undef xmlLineNumbersDefaultValue +int * +__xmlLineNumbersDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlLineNumbersDefaultValue); + else + return (&get_glob_struct()->xmlLineNumbersDefaultValue); +} + +extern int xmlLoadExtDtdDefaultValue; +#undef xmlLoadExtDtdDefaultValue +int * +__xmlLoadExtDtdDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlLoadExtDtdDefaultValue); + else + return (&get_glob_struct()->xmlLoadExtDtdDefaultValue); +} + +extern xmlMallocFunc xmlMalloc; +#undef xmlMalloc +xmlMallocFunc * +__xmlMalloc(void) { + if (IS_MAIN_THREAD) + return (&xmlMalloc); + else + return (&get_glob_struct()->xmlMalloc); +} + +extern xmlStrdupFunc xmlMemStrdup; +#undef xmlMemStrdup +xmlStrdupFunc * +__xmlMemStrdup(void) { + if (IS_MAIN_THREAD) + return (&xmlMemStrdup); + else + return (&get_glob_struct()->xmlMemStrdup); +} + +extern int xmlParserDebugEntities; +#undef xmlParserDebugEntities +int * +__xmlParserDebugEntities(void) { + if (IS_MAIN_THREAD) + return (&xmlParserDebugEntities); + else + return (&get_glob_struct()->xmlParserDebugEntities); +} + +extern const char * xmlParserVersion; +#undef xmlParserVersion +const char * * +__xmlParserVersion(void) { + if (IS_MAIN_THREAD) + return (&xmlParserVersion); + else + return (&get_glob_struct()->xmlParserVersion); +} + +extern int xmlPedanticParserDefaultValue; +#undef xmlPedanticParserDefaultValue +int * +__xmlPedanticParserDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlPedanticParserDefaultValue); + else + return (&get_glob_struct()->xmlPedanticParserDefaultValue); +} + +extern xmlReallocFunc xmlRealloc; +#undef xmlRealloc +xmlReallocFunc * +__xmlRealloc(void) { + if (IS_MAIN_THREAD) + return (&xmlRealloc); + else + return (&get_glob_struct()->xmlRealloc); +} + +extern int xmlSaveNoEmptyTags; +#undef xmlSaveNoEmptyTags +int * +__xmlSaveNoEmptyTags(void) { + if (IS_MAIN_THREAD) + return (&xmlSaveNoEmptyTags); + else + return (&get_glob_struct()->xmlSaveNoEmptyTags); +} + +extern int xmlSubstituteEntitiesDefaultValue; +#undef xmlSubstituteEntitiesDefaultValue +int * +__xmlSubstituteEntitiesDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlSubstituteEntitiesDefaultValue); + else + return (&get_glob_struct()->xmlSubstituteEntitiesDefaultValue); +} diff --git a/include/libxml/Makefile.am b/include/libxml/Makefile.am index 6eb170a8..b145d40e 100644 --- a/include/libxml/Makefile.am +++ b/include/libxml/Makefile.am @@ -29,7 +29,8 @@ xmlinc_HEADERS = \ xmlversion.h \ xmlwin32version.h \ DOCBparser.h \ - catalog.h + catalog.h \ + threads.h install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(xmlincdir) diff --git a/include/libxml/globals.h b/include/libxml/globals.h new file mode 100644 index 00000000..94fdd385 --- /dev/null +++ b/include/libxml/globals.h @@ -0,0 +1,294 @@ +/* + * globals.h: interface for all global variables of the library + * + * The bottom of this file is automatically generated by build_glob.py + * based on the description file global.data + * + * See Copyright for the status of this software. + * + * Gary Pennington + * daniel@veillard.com + */ + +#ifndef __XML_GLOBALS_H +#define __XML_GLOBALS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Externally global symbols which need to be protected for backwards + * compatibility support. + */ +#undef docbDefaultSAXHandler +#undef htmlDefaultSAXHandler +#undef oldXMLWDcompatibility +#undef xmlBufferAllocScheme +#undef xmlDefaultBufferSize +#undef xmlDefaultSAXHandler +#undef xmlDefaultSAXLocator +#undef xmlDoValidityCheckingDefaultValue +#undef xmlFree +#undef xmlGenericError +#undef xmlGenericErrorContext +#undef xmlGetWarningsDefaultValue +#undef xmlIndentTreeOutput +#undef xmlKeepBlanksDefaultValue +#undef xmlLineNumbersDefaultValue +#undef xmlLoadExtDtdDefaultValue +#undef xmlMalloc +#undef xmlMemStrdup +#undef xmlParserDebugEntities +#undef xmlParserVersion +#undef xmlPedanticParserDefaultValue +#undef xmlRealloc +#undef xmlSaveNoEmptyTags +/* #undef xmlStringComment */ +/* #undef xmlStringText */ +/* #undef xmlStringTextNoenc */ +#undef xmlSubstituteEntitiesDefaultValue + +typedef struct _xmlGlobalState xmlGlobalState; +typedef xmlGlobalState *xmlGlobalStatePtr; +struct _xmlGlobalState +{ + xmlSAXHandler docbDefaultSAXHandler; + xmlSAXHandler htmlDefaultSAXHandler; + int oldXMLWDcompatibility; + xmlBufferAllocationScheme xmlBufferAllocScheme; + int xmlDefaultBufferSize; + xmlSAXHandler xmlDefaultSAXHandler; + xmlSAXLocator xmlDefaultSAXLocator; + int xmlDoValidityCheckingDefaultValue; + xmlFreeFunc xmlFree; + xmlGenericErrorFunc xmlGenericError; + void *xmlGenericErrorContext; + int xmlGetWarningsDefaultValue; + int xmlIndentTreeOutput; + int xmlKeepBlanksDefaultValue; + int xmlLineNumbersDefaultValue; + int xmlLoadExtDtdDefaultValue; + xmlMallocFunc xmlMalloc; + xmlStrdupFunc xmlMemStrdup; + int xmlParserDebugEntities; + const char *xmlParserVersion; + int xmlPedanticParserDefaultValue; + xmlReallocFunc xmlRealloc; + int xmlSaveNoEmptyTags; +/* const xmlChar xmlStringComment[8]; */ +/* const xmlChar xmlStringText[5]; */ +/* const xmlChar xmlStringTextNoenc[10]; */ + int xmlSubstituteEntitiesDefaultValue; +}; + +void xmlInitializeGlobalState(xmlGlobalStatePtr gs); + +/* + * Everything starting from the line below is + * Automatically generated by build_glob.py. + * Do not modify the previous line. + */ + + +#ifdef LIBXML_THREAD_ENABLED +extern xmlSAXHandler *__docbDefaultSAXHandler(void); +#define docbDefaultSAXHandler \ +(*(__docbDefaultSAXHandler())) +#else +extern xmlSAXHandler docbDefaultSAXHandler; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlSAXHandler *__htmlDefaultSAXHandler(void); +#define htmlDefaultSAXHandler \ +(*(__htmlDefaultSAXHandler())) +#else +extern xmlSAXHandler htmlDefaultSAXHandler; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__oldXMLWDcompatibility(void); +#define oldXMLWDcompatibility \ +(*(__oldXMLWDcompatibility())) +#else +extern int oldXMLWDcompatibility; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlBufferAllocationScheme *__xmlBufferAllocScheme(void); +#define xmlBufferAllocScheme \ +(*(__xmlBufferAllocScheme())) +#else +extern xmlBufferAllocationScheme xmlBufferAllocScheme; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlDefaultBufferSize(void); +#define xmlDefaultBufferSize \ +(*(__xmlDefaultBufferSize())) +#else +extern int xmlDefaultBufferSize; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlSAXHandler *__xmlDefaultSAXHandler(void); +#define xmlDefaultSAXHandler \ +(*(__xmlDefaultSAXHandler())) +#else +extern xmlSAXHandler xmlDefaultSAXHandler; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlSAXLocator *__xmlDefaultSAXLocator(void); +#define xmlDefaultSAXLocator \ +(*(__xmlDefaultSAXLocator())) +#else +extern xmlSAXLocator xmlDefaultSAXLocator; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlDoValidityCheckingDefaultValue(void); +#define xmlDoValidityCheckingDefaultValue \ +(*(__xmlDoValidityCheckingDefaultValue())) +#else +extern int xmlDoValidityCheckingDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlFreeFunc *__xmlFree(void); +#define xmlFree \ +(*(__xmlFree())) +#else +extern xmlFreeFunc xmlFree; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlGenericErrorFunc *__xmlGenericError(void); +#define xmlGenericError \ +(*(__xmlGenericError())) +#else +extern xmlGenericErrorFunc xmlGenericError; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern void * *__xmlGenericErrorContext(void); +#define xmlGenericErrorContext \ +(*(__xmlGenericErrorContext())) +#else +extern void * xmlGenericErrorContext; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlGetWarningsDefaultValue(void); +#define xmlGetWarningsDefaultValue \ +(*(__xmlGetWarningsDefaultValue())) +#else +extern int xmlGetWarningsDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlIndentTreeOutput(void); +#define xmlIndentTreeOutput \ +(*(__xmlIndentTreeOutput())) +#else +extern int xmlIndentTreeOutput; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlKeepBlanksDefaultValue(void); +#define xmlKeepBlanksDefaultValue \ +(*(__xmlKeepBlanksDefaultValue())) +#else +extern int xmlKeepBlanksDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlLineNumbersDefaultValue(void); +#define xmlLineNumbersDefaultValue \ +(*(__xmlLineNumbersDefaultValue())) +#else +extern int xmlLineNumbersDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlLoadExtDtdDefaultValue(void); +#define xmlLoadExtDtdDefaultValue \ +(*(__xmlLoadExtDtdDefaultValue())) +#else +extern int xmlLoadExtDtdDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlMallocFunc *__xmlMalloc(void); +#define xmlMalloc \ +(*(__xmlMalloc())) +#else +extern xmlMallocFunc xmlMalloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlStrdupFunc *__xmlMemStrdup(void); +#define xmlMemStrdup \ +(*(__xmlMemStrdup())) +#else +extern xmlStrdupFunc xmlMemStrdup; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlParserDebugEntities(void); +#define xmlParserDebugEntities \ +(*(__xmlParserDebugEntities())) +#else +extern int xmlParserDebugEntities; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern const char * *__xmlParserVersion(void); +#define xmlParserVersion \ +(*(__xmlParserVersion())) +#else +extern const char * xmlParserVersion; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlPedanticParserDefaultValue(void); +#define xmlPedanticParserDefaultValue \ +(*(__xmlPedanticParserDefaultValue())) +#else +extern int xmlPedanticParserDefaultValue; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern xmlReallocFunc *__xmlRealloc(void); +#define xmlRealloc \ +(*(__xmlRealloc())) +#else +extern xmlReallocFunc xmlRealloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlSaveNoEmptyTags(void); +#define xmlSaveNoEmptyTags \ +(*(__xmlSaveNoEmptyTags())) +#else +extern int xmlSaveNoEmptyTags; +#endif + +#ifdef LIBXML_THREAD_ENABLED +extern int *__xmlSubstituteEntitiesDefaultValue(void); +#define xmlSubstituteEntitiesDefaultValue \ +(*(__xmlSubstituteEntitiesDefaultValue())) +#else +extern int xmlSubstituteEntitiesDefaultValue; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_GLOBALS_H */ diff --git a/include/libxml/threads.h b/include/libxml/threads.h new file mode 100644 index 00000000..d20b8ffa --- /dev/null +++ b/include/libxml/threads.h @@ -0,0 +1,54 @@ +/** + * threads.c: set of generic threading related routines + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#ifndef __XML_THREADS_H__ +#define __XML_THREADS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlMutex are a simple mutual exception locks + */ +typedef struct _xmlMutex xmlMutex; +typedef xmlMutex *xmlMutexPtr; + +xmlMutexPtr xmlNewMutex (void); +void xmlMutexLock (xmlMutexPtr tok); +void xmlMutexUnlock (xmlMutexPtr tok); +void xmlFreeMutex (xmlMutexPtr tok); + +/* + * xmlRMutex are reentrant mutual exception locks + */ +typedef struct _xmlRMutex xmlRMutex; +typedef xmlRMutex *xmlRMutexPtr; + +xmlRMutexPtr xmlNewRMutex (void); +void xmlRMutexLock (xmlRMutexPtr tok); +void xmlRMutexUnlock (xmlRMutexPtr tok); +void xmlFreeRMutex (xmlRMutexPtr tok); + +/* + * Library wide APIs + */ +void xmlInitThreads (void); +void xmlLockLibrary (void); +void xmlUnlockLibrary(void); +void xmlCleanupThreads(void); +xmlGlobalStatePtr xmlGetGlobalState(void); + +#ifdef __cplusplus +} +#endif + + +#endif /* __XML_THREADS_H__ */ diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in index 58c4ca0e..c5ffc883 100644 --- a/include/libxml/xmlversion.h.in +++ b/include/libxml/xmlversion.h.in @@ -66,6 +66,17 @@ extern void xmlCheckVersion(int version); #define WITHOUT_TRIO #endif +/** + * LIBXML_THREADS_ENABLED: + * + * Whether the thread support is configured in + */ +#if @WITH_THREADS@ +#if defined(_REENTRANT) || (_POSIX_C_SOURCE - 0 >= 199506L) +#define LIBXML_THREAD_ENABLED +#endif +#endif + /** * LIBXML_FTP_ENABLED: * diff --git a/threads.c b/threads.c new file mode 100644 index 00000000..9b0a3464 --- /dev/null +++ b/threads.c @@ -0,0 +1,372 @@ +/** + * threads.c: set of generic threading related routines + * + * See Copyright for the status of this software. + * + * Gary Pennington + * daniel@veillard.com + */ + +#include "libxml.h" + +#include + +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_PTHREAD_H +#include +#endif + +#if defined(SOLARIS) +#include +#endif + + +/* + * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree + * to avoid some crazyness since xmlMalloc/xmlFree may actually + * be hosted on allocated blocks needing them for the allocation ... + */ + +/* + * xmlMutex are a simple mutual exception locks + */ +struct _xmlMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; +#else + int empty; +#endif +}; + +/* + * xmlRMutex are reentrant mutual exception locks + */ +struct _xmlRMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; + unsigned int held; + unsigned int waiters; + pthread_t tid; + pthread_cond_t cv; +#else + int empty; +#endif +}; +/* + * This module still has some internal static data. + * - xmlLibraryLock a global lock + * - globalkey used for per-thread data + * - keylock protecting globalkey + * - keyonce to mark initialization of globalkey + */ +#ifdef HAVE_PTHREAD_H +static pthread_mutex_t keylock; +static pthread_key_t globalkey; +static int keyonce = 0; +#endif +static xmlRMutexPtr xmlLibraryLock = NULL; + +#if defined(SOLARIS) +NOTE(DATA_READABLE_WITHOUT_LOCK(keyonce)) +#endif + +/** + * xmlMutexPtr: + * + * xmlNewMutex() is used to allocate a libxml2 token struct for use in + * synchronizing access to data. + * + * Returns a new simple mutex pointer or NULL in case of error + */ +xmlMutexPtr +xmlNewMutex(void) +{ + xmlMutexPtr tok; + + if ((tok = malloc(sizeof(xmlMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + pthread_mutex_init(&tok->lock, NULL); +#endif + return (tok); +} + +/** + * xmlFreeMutex: + * @tok: the simple mutex + * + * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token + * struct. + */ +void +xmlFreeMutex(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&tok->lock); +#endif + free(tok); +} + +/** + * xmlMutexLock: + * @tok: the simple mutex + * + * xmlMutexLock() is used to lock a libxml2 token. + */ +void +xmlMutexLock(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); +#endif + +} + +/** + * xmlMutexUnlock: + * @tok: the simple mutex + * + * xmlMutexUnlock() is used to unlock a libxml2 token. + */ +void +xmlMutexUnlock(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_unlock(&tok->lock); +#endif +} + +/** + * xmlRNewMutex: + * + * xmlRNewMutex() is used to allocate a reentrant mutex for use in + * synchronizing access to data. token_r is a re-entrant lock and thus useful + * for synchronizing access to data structures that may be manipulated in a + * recursive fashion. + * + * Returns the new reentrant mutex pointer or NULL in case of error + */ +xmlRMutexPtr +xmlNewRMutex(void) +{ + xmlRMutexPtr tok; + + if ((tok = malloc(sizeof(xmlRMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + pthread_mutex_init(&tok->lock, NULL); + tok->held = 0; + tok->waiters = 0; +#endif + return (tok); +} + +/** + * xmlRFreeMutex: + * @tok: the reentrant mutex + * + * xmlRFreeMutex() is used to reclaim resources associated with a + * reentrant mutex. + */ +void +xmlFreeRMutex(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&tok->lock); +#endif + free(tok); +} + +/** + * xmlRMutexLock: + * @tok: the reentrant mutex + * + * xmlRMutexLock() is used to lock a libxml2 token_r. + */ +void +xmlRMutexLock(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); + if (tok->held) { + if (pthread_equal(tok->tid, pthread_self())) { + tok->held++; + pthread_mutex_unlock(&tok->lock); + return; + } else { + tok->waiters++; + while (tok->held) + pthread_cond_wait(&tok->cv, &tok->lock); + tok->waiters--; + } + } + tok->tid = pthread_self(); + tok->held = 1; + pthread_mutex_unlock(&tok->lock); +#endif +} + +/** + * xmlRMutexUnlock: + * @tok: the reentrant mutex + * + * xmlRMutexUnlock() is used to unlock a libxml2 token_r. + */ +void +xmlRMutexUnlock(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); + tok->held--; + if (tok->held == 0) { + if (tok->waiters) + pthread_cond_signal(&tok->cv); + tok->tid = 0; + } + pthread_mutex_unlock(&tok->lock); +#endif +} + +/************************************************************************ + * * + * Per thread global state handling * + * * + ************************************************************************/ + +/** + * xmlFreeGlobalState: + * @state: a thread global state + * + * xmlFreeGlobalState() is called when a thread terminates with a non-NULL + * global state. It is is used here to reclaim memory resources. + */ +static void +xmlFreeGlobalState(void *state) +{ + free(state); +} + +/** + * xmlNewGlobalState: + * + * xmlNewGlobalState() allocates a global state. This structure is used to + * hold all data for use by a thread when supporting backwards compatibility + * of libmxml2 to pre-thread-safe behaviour. + * + * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error + */ +static xmlGlobalStatePtr +xmlNewGlobalState(void) +{ + xmlGlobalState *gs; + + gs = malloc(sizeof(xmlGlobalState)); + if (gs == NULL) + return(NULL); + + memset(gs, 0, sizeof(gs)); + xmlInitializeGlobalState(gs); + return (gs); +} + + +/** + * xmlGetGlobalState: + * + * xmlGetGlobalState() is called to retrieve the global state for a thread. + * keyonce will only be set once during a library invocation and is used + * to create globalkey, the key used to store each thread's TSD. + * + * Note: it should not be called for the "main" thread as this thread uses + * the existing global variables defined in the library. + * + * Returns the thread global state or NULL in case of error + */ +xmlGlobalStatePtr +xmlGetGlobalState(void) +{ +#ifdef HAVE_PTHREAD_H + xmlGlobalState *globalval; + + if (keyonce == 0) { + (void) pthread_mutex_lock(&keylock); + if (keyonce == 0) { + keyonce++; + (void) pthread_key_create(&globalkey, xmlFreeGlobalState); + } + (void) pthread_mutex_unlock(&keylock); + } + if ((globalval = (xmlGlobalState *) + pthread_getspecific(globalkey)) == NULL) { + xmlGlobalState *tsd = xmlNewGlobalState(); + + pthread_setspecific(globalkey, tsd); + return (tsd); + } else + return (globalval); +#endif +} + + +/************************************************************************ + * * + * Library wide thread interfaces * + * * + ************************************************************************/ + +/** + * xmlLockLibrary: + * + * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 + * library. + */ +void +xmlLockLibrary(void) +{ + xmlRMutexLock(xmlLibraryLock); +} + +/** + * xmlUnlockLibrary: + * + * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 + * library. + */ +void +xmlUnlockLibrary(void) +{ + xmlRMutexUnlock(xmlLibraryLock); +} + +/** + * xmlInitThreads: + * + * xmlInitThreads() is used to to initialize all the thread related + * data of the libxml2 library. + */ +void +xmlInitThreads(void) +{ +} + +/** + * xmlCleanupThreads: + * + * xmlCleanupThreads() is used to to cleanup all the thread related + * data of the libxml2 library once processing has ended. + */ +void +xmlCleanupThreads(void) +{ +} diff --git a/xmlcatalog.c b/xmlcatalog.c index 80635450..b76719d9 100644 --- a/xmlcatalog.c +++ b/xmlcatalog.c @@ -370,9 +370,11 @@ int main(int argc, char **argv) { } else if (argv[i][0] == '-') continue; filename = argv[i]; + /* !!!!!!!!!!!!!!!!!! TODO !!!! if (sgml) ret = xmlLoadSGMLSuperCatalog(argv[i]); else + !!!!!!!!! */ ret = xmlLoadCatalog(argv[i]); if ((!sgml) && (ret < 0) && (create)) { xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL);