summaryrefslogtreecommitdiff
path: root/xsltproc
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@redhat.com>2009-08-14 08:58:50 +0200
committerDaniel Veillard <veillard@redhat.com>2009-08-14 08:58:50 +0200
commit52588cf2f11ce43a184cc3c54fbe50dea19930da (patch)
treedca951b8ac15bba3fd3609c9cd63153010e7fe09 /xsltproc
parent9d0f428e4daa0fd880dc9cc8a9417adf41a3106a (diff)
downloadlibxslt-52588cf2f11ce43a184cc3c54fbe50dea19930da.tar.gz
libxslt-52588cf2f11ce43a184cc3c54fbe50dea19930da.tar.bz2
libxslt-52588cf2f11ce43a184cc3c54fbe50dea19930da.zip
Adding a test program to check thread reentrancy
* xsltproc/testThreads.c: based loosely on libxml2 one, checks concurrent use of the same stylesheet and extensions reentrancy * config.h.in configure.in: we need to check for pthreads * Makefile.am xsltproc/Makefile.am: add the new program and insert in make check
Diffstat (limited to 'xsltproc')
-rw-r--r--xsltproc/Makefile.am10
-rw-r--r--xsltproc/testThreads.c263
2 files changed, 273 insertions, 0 deletions
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