mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-07-31 02:43:06 +03:00
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
This commit is contained in:
@ -47,12 +47,14 @@ dummy:
|
|||||||
tests: dummy
|
tests: dummy
|
||||||
@echo '## Running the regression test suite'
|
@echo '## Running the regression test suite'
|
||||||
@(cd tests ; $(MAKE) MAKEFLAGS+=--silent tests)
|
@(cd tests ; $(MAKE) MAKEFLAGS+=--silent tests)
|
||||||
|
@(cd xsltproc ; $(MAKE) MAKEFLAGS+=--silent tests)
|
||||||
@(if [ "@PYTHON_SUBDIR@" != "" ] ; then cd python ; $(MAKE) MAKEFLAGS+=--silent tests ; fi)
|
@(if [ "@PYTHON_SUBDIR@" != "" ] ; then cd python ; $(MAKE) MAKEFLAGS+=--silent tests ; fi)
|
||||||
|
|
||||||
valgrind:
|
valgrind:
|
||||||
@echo '## Running the regression tests under Valgrind'
|
@echo '## Running the regression tests under Valgrind'
|
||||||
@echo '## Go get a cup of coffee it is gonna take a while ...'
|
@echo '## Go get a cup of coffee it is gonna take a while ...'
|
||||||
@(cd tests ; $(MAKE) CHECKER='valgrind -q' tests)
|
@(cd tests ; $(MAKE) CHECKER='valgrind -q' tests)
|
||||||
|
@(cd xsltproc ; $(MAKE) CHECKER='valgrind -q' tests)
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
-@(find . -name .\#\* -exec rm {} \;)
|
-@(find . -name .\#\* -exec rm {} \;)
|
||||||
|
43
config.h.in
43
config.h.in
@ -42,6 +42,9 @@
|
|||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
#undef HAVE_INTTYPES_H
|
#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. */
|
/* Define to 1 if you have the <locale.h> header file. */
|
||||||
#undef HAVE_LOCALE_H
|
#undef HAVE_LOCALE_H
|
||||||
|
|
||||||
@ -66,6 +69,9 @@
|
|||||||
/* Define to 1 if you have the `printf' function. */
|
/* Define to 1 if you have the `printf' function. */
|
||||||
#undef HAVE_PRINTF
|
#undef HAVE_PRINTF
|
||||||
|
|
||||||
|
/* Define if <pthread.h> is there */
|
||||||
|
#undef HAVE_PTHREAD_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `snprintf' function. */
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
#undef HAVE_SNPRINTF
|
#undef HAVE_SNPRINTF
|
||||||
|
|
||||||
@ -132,6 +138,10 @@
|
|||||||
/* Define to 1 if you have the `_stat' function. */
|
/* Define to 1 if you have the `_stat' function. */
|
||||||
#undef HAVE__STAT
|
#undef HAVE__STAT
|
||||||
|
|
||||||
|
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||||
|
*/
|
||||||
|
#undef LT_OBJDIR
|
||||||
|
|
||||||
/* Name of package */
|
/* Name of package */
|
||||||
#undef PACKAGE
|
#undef PACKAGE
|
||||||
|
|
||||||
@ -153,13 +163,40 @@
|
|||||||
/* Define to 1 if you have the ANSI C header files. */
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
#undef STDC_HEADERS
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
/* Version number of package */
|
/* Enable extensions on AIX 3, Interix. */
|
||||||
#undef VERSION
|
#ifndef _ALL_SOURCE
|
||||||
|
# undef _ALL_SOURCE
|
||||||
|
#endif
|
||||||
/* Enable GNU extensions on systems that have them. */
|
/* Enable GNU extensions on systems that have them. */
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
# undef _GNU_SOURCE
|
# undef _GNU_SOURCE
|
||||||
#endif
|
#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 */
|
/* Using the Win32 Socket implementation */
|
||||||
#undef _WINSOCKAPI_
|
#undef _WINSOCKAPI_
|
||||||
|
@ -119,6 +119,12 @@ AM_PROG_LIBTOOL
|
|||||||
|
|
||||||
AC_CHECK_HEADERS(sys/types.h sys/time.h stdlib.h unistd.h string.h)
|
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
|
||||||
dnl Detect supported locale
|
dnl Detect supported locale
|
||||||
dnl
|
dnl
|
||||||
|
@ -5,12 +5,19 @@ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \
|
|||||||
EXTRA_PROGRAMS=
|
EXTRA_PROGRAMS=
|
||||||
bin_PROGRAMS = xsltproc $(XSLTPROCDV)
|
bin_PROGRAMS = xsltproc $(XSLTPROCDV)
|
||||||
|
|
||||||
|
noinst_PROGRAMS=testThreads
|
||||||
|
|
||||||
AM_CFLAGS = $(LIBGCRYPT_CFLAGS)
|
AM_CFLAGS = $(LIBGCRYPT_CFLAGS)
|
||||||
|
|
||||||
xsltproc_SOURCES = xsltproc.c
|
xsltproc_SOURCES = xsltproc.c
|
||||||
xsltproc_LDFLAGS =
|
xsltproc_LDFLAGS =
|
||||||
xsltproc_DEPENDENCIES = $(DEPS)
|
xsltproc_DEPENDENCIES = $(DEPS)
|
||||||
|
|
||||||
|
testThreads_SOURCES=testThreads.c
|
||||||
|
testThreads_LDFLAGS =
|
||||||
|
testThreads_DEPENDENCIES = $(DEPS)
|
||||||
|
testThreads_LDADD= $(LDADDS)
|
||||||
|
|
||||||
DEPS = $(top_builddir)/libxslt/libxslt.la \
|
DEPS = $(top_builddir)/libxslt/libxslt.la \
|
||||||
$(top_builddir)/libexslt/libexslt.la
|
$(top_builddir)/libexslt/libexslt.la
|
||||||
|
|
||||||
@ -24,3 +31,6 @@ xsltproc_LDADD = $(LIBGCRYPT_LIBS) $(LDADDS)
|
|||||||
xsltproc.dv: xsltproc.o
|
xsltproc.dv: xsltproc.o
|
||||||
$(CC) $(CFLAGS) -o xsltproc xsltproc.o ../libexslt/.libs/libexslt.a ../libxslt/.libs/libxslt.a @LIBXML_LIBS@ $(EXTRA_LIBS) $(LIBGCRYPT_LIBS)
|
$(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)
|
||||||
|
263
xsltproc/testThreads.c
Normal file
263
xsltproc/testThreads.c
Normal file
@ -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
|
Reference in New Issue
Block a user