diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | config.h.in | 43 | ||||
-rw-r--r-- | configure.in | 6 | ||||
-rw-r--r-- | xsltproc/Makefile.am | 10 | ||||
-rw-r--r-- | xsltproc/testThreads.c | 263 |
5 files changed, 321 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index 839d4e5a..60bc051a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,12 +47,14 @@ dummy: tests: dummy @echo '## Running the regression test suite' @(cd tests ; $(MAKE) MAKEFLAGS+=--silent tests) + @(cd xsltproc ; $(MAKE) MAKEFLAGS+=--silent tests) @(if [ "@PYTHON_SUBDIR@" != "" ] ; then cd python ; $(MAKE) MAKEFLAGS+=--silent tests ; fi) valgrind: @echo '## Running the regression tests under Valgrind' @echo '## Go get a cup of coffee it is gonna take a while ...' @(cd tests ; $(MAKE) CHECKER='valgrind -q' tests) + @(cd xsltproc ; $(MAKE) CHECKER='valgrind -q' tests) cleanup: -@(find . -name .\#\* -exec rm {} \;) diff --git a/config.h.in b/config.h.in index 7b8783da..b3e2dd55 100644 --- a/config.h.in +++ b/config.h.in @@ -42,6 +42,9 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H +/* Define if pthread library is there (-lpthread) */ +#undef HAVE_LIBPTHREAD + /* Define to 1 if you have the <locale.h> header file. */ #undef HAVE_LOCALE_H @@ -66,6 +69,9 @@ /* Define to 1 if you have the `printf' function. */ #undef HAVE_PRINTF +/* Define if <pthread.h> is there */ +#undef HAVE_PTHREAD_H + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF @@ -132,6 +138,10 @@ /* Define to 1 if you have the `_stat' function. */ #undef HAVE__STAT +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + /* Name of package */ #undef PACKAGE @@ -153,13 +163,40 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS -/* Version number of package */ -#undef VERSION - +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE /* Using the Win32 Socket implementation */ #undef _WINSOCKAPI_ diff --git a/configure.in b/configure.in index 92edb867..60f189f4 100644 --- a/configure.in +++ b/configure.in @@ -119,6 +119,12 @@ AM_PROG_LIBTOOL AC_CHECK_HEADERS(sys/types.h sys/time.h stdlib.h unistd.h string.h) +dnl Look for pthread.h, needed for testThreads +AC_CHECK_HEADER(pthread.h, + AC_CHECK_LIB(pthread, pthread_join,[ + AC_DEFINE([HAVE_LIBPTHREAD], [], [Define if pthread library is there (-lpthread)]) + AC_DEFINE([HAVE_PTHREAD_H], [], [Define if <pthread.h> is there]) ])) + dnl dnl Detect supported locale dnl diff --git a/xsltproc/Makefile.am b/xsltproc/Makefile.am index 65553587..7eb01e4b 100644 --- a/xsltproc/Makefile.am +++ b/xsltproc/Makefile.am @@ -5,12 +5,19 @@ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \ EXTRA_PROGRAMS= bin_PROGRAMS = xsltproc $(XSLTPROCDV) +noinst_PROGRAMS=testThreads + AM_CFLAGS = $(LIBGCRYPT_CFLAGS) xsltproc_SOURCES = xsltproc.c xsltproc_LDFLAGS = xsltproc_DEPENDENCIES = $(DEPS) +testThreads_SOURCES=testThreads.c +testThreads_LDFLAGS = +testThreads_DEPENDENCIES = $(DEPS) +testThreads_LDADD= $(LDADDS) + DEPS = $(top_builddir)/libxslt/libxslt.la \ $(top_builddir)/libexslt/libexslt.la @@ -24,3 +31,6 @@ xsltproc_LDADD = $(LIBGCRYPT_LIBS) $(LDADDS) xsltproc.dv: xsltproc.o $(CC) $(CFLAGS) -o xsltproc xsltproc.o ../libexslt/.libs/libexslt.a ../libxslt/.libs/libxslt.a @LIBXML_LIBS@ $(EXTRA_LIBS) $(LIBGCRYPT_LIBS) +tests: testThreads + @echo '## Running testThreads' + @($(CHECKER) ./testThreads ; grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0" || true) diff --git a/xsltproc/testThreads.c b/xsltproc/testThreads.c new file mode 100644 index 00000000..6c00ef47 --- /dev/null +++ b/xsltproc/testThreads.c @@ -0,0 +1,263 @@ +/** + * testThreads.c: testing of heavilly multithreaded concurrent accesses + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +/* + * TODO: extend it to allow giving the stylesheets/input as filenames on the + * command line to test specifics, also add exslt + */ + +#include "config.h" +#include <stdlib.h> +#include <stdio.h> + +#define _REENTRANT +#include <libxml/xmlversion.h> + +#if defined(LIBXML_THREAD_ENABLED) && defined(HAVE_PTHREAD_H) + +#include <libxml/globals.h> +#include <libxml/threads.h> +#include <libxml/parser.h> +#include <libxml/catalog.h> +#include <libxml/xpathInternals.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> +#include <libxslt/extensions.h> +#include <pthread.h> +#include <string.h> +#if !defined(_MSC_VER) +#include <unistd.h> +#endif +#include <assert.h> + +#define MAX_ARGC 20 + +static pthread_t tid[MAX_ARGC]; + +#define EXT_NS BAD_CAST "http://foo.org" +#define EXT_DATA "bar" + +const char *stylesheet = "<xsl:stylesheet version='1.0' \ +xmlns:xsl='http://www.w3.org/1999/XSL/Transform' \ +xmlns:foo='http://foo.org' \ +extension-element-prefixes='foo'>\ +<xsl:template match='text()'>\ +Success <xsl:value-of select='foo:foo()'/>\ +</xsl:template>\ +</xsl:stylesheet>\ +"; + +int init = 0; + +const char *doc = "<doc>Failed</doc>"; +const char *expect = "<?xml version=\"1.0\"?>\nSuccess foo\n"; + +static void fooFunction(xmlXPathParserContextPtr ctxt, + int nargs ATTRIBUTE_UNUSED) { + xmlXPathReturnString(ctxt, xmlStrdup(BAD_CAST "foo")); +} + +static +void * registerFooExtensions(ATTRIBUTE_UNUSED xsltTransformContextPtr ctxt, + ATTRIBUTE_UNUSED const xmlChar *URI) { + xsltRegisterExtModuleFunction(BAD_CAST "foo", EXT_NS, fooFunction); + return((void *)EXT_DATA); +} + +static +void shutdownFooExtensions(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *URI, void *data) { + const char *str = (const char *) data; + if (!xmlStrEqual(URI, EXT_NS)) { + fprintf(stderr, "Mismatch in extensions shutdown URI"); + } + if (!xmlStrEqual(BAD_CAST str, BAD_CAST EXT_DATA)) { + fprintf(stderr, "Mismatch in extensions shutdown DATA"); + } +} + +static void registerFooModule(void) { + xsltRegisterExtModule(EXT_NS, registerFooExtensions, shutdownFooExtensions); +} + +static void * +threadRoutine1(void *data) +{ + xmlDocPtr input; + xmlDocPtr style; + xmlDocPtr res; + xmlChar *result; + int len; + xsltStylesheetPtr cur; + int id = (int)(unsigned long) data; + + input = xmlReadMemory(doc, strlen(doc), "doc.xml", NULL, 0); + if (input == NULL) { + fprintf(stderr, "Thread id %d failed to parse input\n", id); + exit(1); + } + style = xmlReadMemory(stylesheet, strlen(stylesheet), "doc.xsl", NULL, 0); + if (style == NULL) { + fprintf(stderr, "Thread id %d failed to parse stylesheet\n", id); + exit(1); + } + cur = xsltParseStylesheetDoc(style); + if (cur == NULL) { + fprintf(stderr, "Thread id %d failed to compile stylesheet\n", id); + exit(1); + } + res = xsltApplyStylesheet(cur, input, NULL); + if (res == NULL) { + fprintf(stderr, "Thread id %d failed to apply stylesheet\n", id); + exit(1); + } + if (xsltSaveResultToString(&result, &len, res, cur) < 0) { + fprintf(stderr, "Thread id %d failed to output result\n", id); + exit(1); + } + if (!xmlStrEqual(BAD_CAST expect, result)) { + fprintf(stderr, "Thread id %d output not conform\n", id); + exit(1); + } + xsltFreeStylesheet(cur); + xmlFreeDoc(input); + xmlFreeDoc(res); + xmlFree(result); + return(0); +} + +static void * +threadRoutine2(void *data) +{ + xmlDocPtr input; + xmlDocPtr res; + xmlChar *result; + int len; + xsltStylesheetPtr cur = (xsltStylesheetPtr) data; + + if (cur == NULL) { + fprintf(stderr, "Thread failed to get the stylesheet\n"); + exit(1); + } + input = xmlReadMemory(doc, strlen(doc), "doc.xml", NULL, 0); + if (input == NULL) { + fprintf(stderr, "Thread failed to parse input\n"); + exit(1); + } + res = xsltApplyStylesheet(cur, input, NULL); + if (res == NULL) { + fprintf(stderr, "Thread failed to apply stylesheet\n"); + exit(1); + } + if (xsltSaveResultToString(&result, &len, res, cur) < 0) { + fprintf(stderr, "Thread failed to output result\n"); + exit(1); + } + if (!xmlStrEqual(BAD_CAST expect, result)) { + fprintf(stderr, "Thread output not conform\n"); + exit(1); + } + xmlFreeDoc(input); + xmlFreeDoc(res); + xmlFree(result); + return(0); +} +int +main(void) +{ + unsigned int i, repeat; + unsigned int num_threads = 8; + void *results[MAX_ARGC]; + int ret; + + xmlInitParser(); + + registerFooModule(); + + /* + * First pass each thread has its own version of the stylesheet + * each of them will initialize and shutdown the extension + */ + for (repeat = 0;repeat < 500;repeat++) { + for (i = 0; i < num_threads; i++) { + results[i] = NULL; + tid[i] = (pthread_t) -1; + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&tid[i], NULL, threadRoutine1, + (void *) (unsigned long) i); + if (ret != 0) { + perror("pthread_create"); + exit(1); + } + } + for (i = 0; i < num_threads; i++) { + ret = pthread_join(tid[i], &results[i]); + if (ret != 0) { + perror("pthread_join"); + exit(1); + } + } + } + + /* + * Second pass all threads share the same stylesheet instance + * look for transformation clashes + */ + for (repeat = 0;repeat < 500;repeat++) { + xmlDocPtr style; + xsltStylesheetPtr cur; + + style = xmlReadMemory(stylesheet, strlen(stylesheet), "doc.xsl", + NULL, 0); + if (style == NULL) { + fprintf(stderr, "Main failed to parse stylesheet\n"); + exit(1); + } + cur = xsltParseStylesheetDoc(style); + if (cur == NULL) { + fprintf(stderr, "Main failed to compile stylesheet\n"); + exit(1); + } + for (i = 0; i < num_threads; i++) { + results[i] = NULL; + tid[i] = (pthread_t) -1; + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&tid[i], NULL, threadRoutine2, (void *) cur); + if (ret != 0) { + perror("pthread_create"); + exit(1); + } + } + for (i = 0; i < num_threads; i++) { + ret = pthread_join(tid[i], &results[i]); + if (ret != 0) { + perror("pthread_join"); + exit(1); + } + } + xsltFreeStylesheet(cur); + } + xsltCleanupGlobals(); + xmlCleanupParser(); + xmlMemoryDump(); + return (0); +} +#else /* !LIBXML_THREADS_ENABLED | !HAVE_PTHREAD_H */ +int +main(void) +{ + fprintf(stderr, "libxml was not compiled with thread\n"); + return (0); +} +#endif |