1/**
2 * testThreads.c: testing of heavilly multithreaded concurrent accesses
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9/*
10 * TODO: extend it to allow giving the stylesheets/input as filenames on the
11 *       command line to test specifics, also add exslt
12 */
13
14#include "config.h"
15#include "libexslt/exslt.h"
16#include <stdlib.h>
17#include <stdio.h>
18
19#define _REENTRANT
20#include <libxml/xmlversion.h>
21
22#if defined(LIBXML_THREAD_ENABLED) && defined(HAVE_PTHREAD_H)
23
24#include <libxml/globals.h>
25#include <libxml/threads.h>
26#include <libxml/parser.h>
27#include <libxml/catalog.h>
28#include <libxml/xpathInternals.h>
29#include <libxslt/xslt.h>
30#include <libxslt/xsltInternals.h>
31#include <libxslt/transform.h>
32#include <libxslt/xsltutils.h>
33#include <libxslt/extensions.h>
34#include <libexslt/exsltconfig.h>
35#include <pthread.h>
36#include <string.h>
37#if !defined(_MSC_VER)
38#include <unistd.h>
39#endif
40#include <assert.h>
41
42#define	MAX_ARGC	20
43
44static pthread_t tid[MAX_ARGC];
45
46#define EXT_NS BAD_CAST "http://foo.org"
47#define EXT_DATA "bar"
48
49const char *stylesheet = "<xsl:stylesheet version='1.0' \
50xmlns:xsl='http://www.w3.org/1999/XSL/Transform' \
51xmlns:foo='http://foo.org' \
52extension-element-prefixes='foo'>\
53<xsl:template match='text()'>\
54Success <xsl:value-of select='foo:foo()'/>\
55</xsl:template>\
56</xsl:stylesheet>\
57";
58
59int init = 0;
60
61const char *doc = "<doc>Failed</doc>";
62const char *expect = "<?xml version=\"1.0\"?>\nSuccess foo\n";
63
64static void fooFunction(xmlXPathParserContextPtr ctxt,
65                        int nargs ATTRIBUTE_UNUSED) {
66    xmlXPathReturnString(ctxt, xmlStrdup(BAD_CAST "foo"));
67}
68
69static
70void * registerFooExtensions(ATTRIBUTE_UNUSED xsltTransformContextPtr ctxt,
71                             ATTRIBUTE_UNUSED const xmlChar *URI) {
72    xsltRegisterExtModuleFunction(BAD_CAST "foo", EXT_NS, fooFunction);
73    return((void *)EXT_DATA);
74}
75
76static
77void shutdownFooExtensions(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
78                           const xmlChar *URI, void *data) {
79    const char *str = (const char *) data;
80    if (!xmlStrEqual(URI, EXT_NS)) {
81        fprintf(stderr, "Mismatch in extensions shutdown URI");
82    }
83    if (!xmlStrEqual(BAD_CAST str, BAD_CAST EXT_DATA)) {
84        fprintf(stderr, "Mismatch in extensions shutdown DATA");
85    }
86}
87
88static void registerFooModule(void) {
89    xsltRegisterExtModule(EXT_NS, registerFooExtensions, shutdownFooExtensions);
90}
91
92static void *
93threadRoutine1(void *data)
94{
95    xmlDocPtr input;
96    xmlDocPtr style;
97    xmlDocPtr res;
98    xmlChar *result;
99    int len;
100    xsltStylesheetPtr cur;
101    int id = (int)(unsigned long) data;
102
103    input = xmlReadMemory(doc, strlen(doc), "doc.xml", NULL, 0);
104    if (input == NULL) {
105        fprintf(stderr, "Thread id %d failed to parse input\n", id);
106        exit(1);
107    }
108    style = xmlReadMemory(stylesheet, strlen(stylesheet), "doc.xsl", NULL, 0);
109    if (style == NULL) {
110        fprintf(stderr, "Thread id %d failed to parse stylesheet\n", id);
111        exit(1);
112    }
113    cur = xsltParseStylesheetDoc(style);
114    if (cur == NULL) {
115        fprintf(stderr, "Thread id %d failed to compile stylesheet\n", id);
116        exit(1);
117    }
118    res = xsltApplyStylesheet(cur, input, NULL);
119    if (res == NULL) {
120        fprintf(stderr, "Thread id %d failed to apply stylesheet\n", id);
121        exit(1);
122    }
123    if (xsltSaveResultToString(&result, &len, res, cur) < 0) {
124        fprintf(stderr, "Thread id %d failed to output result\n", id);
125        exit(1);
126    }
127    if (!xmlStrEqual(BAD_CAST expect, result)) {
128        fprintf(stderr, "Thread id %d output not conform\n", id);
129        exit(1);
130    }
131    xsltFreeStylesheet(cur);
132    xmlFreeDoc(input);
133    xmlFreeDoc(res);
134    xmlFree(result);
135    return(0);
136}
137
138static void *
139threadRoutine2(void *data)
140{
141    xmlDocPtr input;
142    xmlDocPtr res;
143    xmlChar *result;
144    int len;
145    xsltStylesheetPtr cur = (xsltStylesheetPtr) data;
146
147    if (cur == NULL) {
148        fprintf(stderr, "Thread failed to get the stylesheet\n");
149        exit(1);
150    }
151    input = xmlReadMemory(doc, strlen(doc), "doc.xml", NULL, 0);
152    if (input == NULL) {
153        fprintf(stderr, "Thread failed to parse input\n");
154        exit(1);
155    }
156    res = xsltApplyStylesheet(cur, input, NULL);
157    if (res == NULL) {
158        fprintf(stderr, "Thread failed to apply stylesheet\n");
159        exit(1);
160    }
161    if (xsltSaveResultToString(&result, &len, res, cur) < 0) {
162        fprintf(stderr, "Thread failed to output result\n");
163        exit(1);
164    }
165    if (!xmlStrEqual(BAD_CAST expect, result)) {
166        fprintf(stderr, "Thread output not conform\n");
167        exit(1);
168    }
169    xmlFreeDoc(input);
170    xmlFreeDoc(res);
171    xmlFree(result);
172    return(0);
173}
174int
175main(void)
176{
177    unsigned int i, repeat;
178    unsigned int num_threads = 8;
179    void *results[MAX_ARGC];
180    int ret;
181
182    xmlInitParser();
183
184    /*
185     * Register the EXSLT extensions and the test module
186     */
187    exsltRegisterAll();
188    xsltRegisterTestModule();
189
190    /*
191     * Register our own extension module
192     */
193    registerFooModule();
194
195    /*
196     * First pass each thread has its own version of the stylesheet
197     * each of them will initialize and shutdown the extension
198     */
199    printf("Pass 1\n");
200    for (repeat = 0;repeat < 500;repeat++) {
201        memset(results, 0, sizeof(*results)*num_threads);
202        memset(tid, 0xff, sizeof(*tid)*num_threads);
203
204	for (i = 0; i < num_threads; i++) {
205	    ret = pthread_create(&tid[i], NULL, threadRoutine1,
206                                 (void *) (unsigned long) i);
207	    if (ret != 0) {
208		perror("pthread_create");
209		exit(1);
210	    }
211	}
212	for (i = 0; i < num_threads; i++) {
213	    ret = pthread_join(tid[i], &results[i]);
214	    if (ret != 0) {
215		perror("pthread_join");
216		exit(1);
217	    }
218	}
219    }
220
221    /*
222     * Second pass all threads share the same stylesheet instance
223     * look for transformation clashes
224     */
225    printf("Pass 2\n");
226    for (repeat = 0;repeat < 500;repeat++) {
227        xmlDocPtr style;
228        xsltStylesheetPtr cur;
229
230        style = xmlReadMemory(stylesheet, strlen(stylesheet), "doc.xsl",
231                               NULL, 0);
232        if (style == NULL) {
233            fprintf(stderr, "Main failed to parse stylesheet\n");
234            exit(1);
235        }
236        cur = xsltParseStylesheetDoc(style);
237        if (cur == NULL) {
238            fprintf(stderr, "Main failed to compile stylesheet\n");
239            exit(1);
240        }
241        memset(results, 0, sizeof(*results)*num_threads);
242        memset(tid, 0xff, sizeof(*tid)*num_threads);
243
244	for (i = 0; i < num_threads; i++) {
245	    ret = pthread_create(&tid[i], NULL, threadRoutine2, (void *) cur);
246	    if (ret != 0) {
247		perror("pthread_create");
248		exit(1);
249	    }
250	}
251	for (i = 0; i < num_threads; i++) {
252	    ret = pthread_join(tid[i], &results[i]);
253	    if (ret != 0) {
254		perror("pthread_join");
255		exit(1);
256	    }
257	}
258        xsltFreeStylesheet(cur);
259    }
260    xsltCleanupGlobals();
261    xmlCleanupParser();
262    xmlMemoryDump();
263    printf("Ok\n");
264    return (0);
265}
266#else /* !LIBXML_THREADS_ENABLED | !HAVE_PTHREAD_H */
267int
268main(void)
269{
270    fprintf(stderr, "libxml was not compiled with thread\n");
271    return (0);
272}
273#endif
274