/** * 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 "libexslt/exslt.h" #include #include #ifndef _REENTRANT #define _REENTRANT #endif #include #if defined(LIBXML_THREAD_ENABLED) && defined(HAVE_PTHREAD_H) #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(_MSC_VER) #include #endif #include #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 = "\ \ Success \ \ \ "; int init = 0; const char *doc = "Failed"; const char *expect = "\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(); /* * Register the EXSLT extensions and the test module */ exsltRegisterAll(); xsltRegisterTestModule(); /* * Register our own extension module */ registerFooModule(); /* * First pass each thread has its own version of the stylesheet * each of them will initialize and shutdown the extension */ printf("Pass 1\n"); for (repeat = 0;repeat < 500;repeat++) { memset(results, 0, sizeof(*results)*num_threads); memset(tid, 0xff, sizeof(*tid)*num_threads); 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 */ printf("Pass 2\n"); 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); } memset(results, 0, sizeof(*results)*num_threads); memset(tid, 0xff, sizeof(*tid)*num_threads); 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(); printf("Ok\n"); return (0); } #else /* !LIBXML_THREADS_ENABLED | !HAVE_PTHREAD_H */ int main(void) { fprintf(stderr, "libxml was not compiled with thread\n"); return (0); } #endif