Skip to content
Snippets Groups Projects
ThreadTest.cpp 45.8 KiB
Newer Older
Andy Heninger's avatar
Andy Heninger committed
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
/*
 * $Id$
 *
 * @author Andy Heninger, IBM
 */
Andy Heninger's avatar
Andy Heninger committed
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/Attributes.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>

PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/dom/DOM.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
#include <xercesc/internal/MemoryManagerImpl.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
Tinny Ng's avatar
Tinny Ng committed
void clearFileInfoMemory();
Andy Heninger's avatar
Andy Heninger committed
#include <pthread.h>
#include <unistd.h>
#include <errno.h>


//------------------------------------------------------------------------------
//
//   UNIX specific code for starting threads
//
//------------------------------------------------------------------------------
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
extern "C" {

Andy Heninger's avatar
Andy Heninger committed
typedef void (*ThreadFunc)(void *);
typedef void *(*pthreadfunc)(void *);

class ThreadFuncs           // This class isolates OS dependent threading
{                           //   functions from the rest of ThreadTest program.
public:
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
    static void Sleep(int millis);
Andy Heninger's avatar
Andy Heninger committed
    static void startThread(ThreadFunc, void *param);
};

void ThreadFuncs::Sleep(int millis)
{
   int seconds = millis/1000;
   if (seconds <= 0) seconds = 1;
#if defined(SOLARIS)
   // somehow the sleep hangs on Solaris
   // so ignore the call
#else
Andy Heninger's avatar
Andy Heninger committed
   ::sleep(seconds);
Andy Heninger's avatar
Andy Heninger committed


void ThreadFuncs::startThread(ThreadFunc func, void *param)
{
#if defined(_HP_UX) && defined(XML_USE_DCE)
    x = pthread_create( &tId, pthread_attr_default,  (pthreadfunc)func,  param);
#else
    pthread_attr_t attr;
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
    pthread_attr_init(&attr);
Andy Heninger's avatar
Andy Heninger committed
    x = pthread_create( &tId, &attr,  (pthreadfunc)func,  param);
Andy Heninger's avatar
Andy Heninger committed
    if (x == -1)
    {
        fprintf(stderr, "Error starting thread.  Errno = %d\n", errno);
Tinny Ng's avatar
Tinny Ng committed
        clearFileInfoMemory();
Andy Heninger's avatar
Andy Heninger committed
        exit(-1);
    }

//------------------------------------------------------------------------------
//
//   Windows specific code for starting threads
//
//------------------------------------------------------------------------------

#include <Windows.h>
#include <process.h>

typedef DWORD (WINAPI *ThreadFunc)(void *);

class ThreadFuncs           // This class isolates OS dependent threading
{                           //   functions from the rest of ThreadTest program.
public:
    static void Sleep(int millis) {::Sleep(millis);};
    static void startThread(ThreadFunc, void *param);
};

void ThreadFuncs::startThread(ThreadFunc func, void *param)
{
    HANDLE  tHandle;
    DWORD   threadID;

    tHandle = CreateThread(0,          // Security Attributes,
                           0x10000,    // Stack Size,
                           func,       // Starting Address.
                           param,      // Parmeters
                           0,          // Creation Flags,
                           &threadID); // Thread ID (Can not be null on 95/98)

    if (tHandle == 0)
    {
        fprintf(stderr, "Error starting thread.  Errno = %d\n", errno);
        clearFileInfoMemory();
        exit(-1);
    }

    // Set the priority of the working threads low, so that the UI of the running system will
    //   remain responsive.
    SetThreadPriority(tHandle, THREAD_PRIORITY_IDLE);
}

//------------------------------------------------------------------------------
//
//  struct InFileInfo   One of these structs will be set up for each file listed
//                      on the command line.  Once set, the data is unchanging
//                      and can safely be referenced by the test threads without
//                      use of synchronization.
//
//------------------------------------------------------------------------------
struct InFileInfo
{
    char    *fileName;
Tinny Ng's avatar
Tinny Ng committed
    XMLCh   *uFileName;      // When doing an in-memory parse, avoid transcoding file name
                             //    each time through.
    char    *fileContent;    // If doing an in-memory parse, this field points
                             //   to an allocated string containing the entire file
                             //   contents.  Otherwise it's 0.
    size_t  fileSize;        // The file length.  Only initialized when doing
                             //   an in-memory test.
    int     checkSum;        // The XML checksum.  Set up by the main thread for
                             //   each file before the worker threads are started.
};

Andy Heninger's avatar
Andy Heninger committed

//------------------------------------------------------------------------------
//
//  struct threadInfo  Holds information specific to an individual thread.
//                     One of these is set up for each thread in the test.
//                     The main program monitors the threads by looking
//                     at the status stored in these structs.
//
//------------------------------------------------------------------------------
struct ThreadInfo
{
    bool            fHeartBeat;   // Set true by the thread each time it finishes
                                  //   parsing a file.
    bool            fInProgress;  // Set to false by the thread when parse in progress
    unsigned int    fParses;      // Number of parses completed.
    int             fThreadNum;   // Identifying number for this thread.
Andy Heninger's avatar
Andy Heninger committed
    ThreadInfo() {
        fHeartBeat = false;
Andy Heninger's avatar
Andy Heninger committed
        fParses = 0;
        fThreadNum = -1;
    }
};


XERCES_CPP_NAMESPACE_USE
//------------------------------------------------------------------------------
//
//  struct runInfo     Holds the info extracted from the command line.
//                     There is only one of these, and it is static, and
//                     unchanging once the command line has been parsed.
//                     During the test, the threads will access this info without
//                     any synchronization.
//
//------------------------------------------------------------------------------
const int MAXINFILES = 25;
struct RunInfo
    bool                            stopNow;
    bool                            dom;
    bool                            sax;
    bool                            reuseParser;
    bool                            inMemory;
    bool                            dumpOnErr;
    bool                            doSchema;
    bool                            schemaFullChecking;
    bool                            doNamespaces;
    bool                            doInitialParse;
    bool                            doNamespacePrefixes;  // SAX2
    SAXParser::ValSchemes           valScheme;
    int                             numThreads;
    int                             totalTime;
    int                             numInputFiles;
    unsigned int                    numParses;
    InFileInfo                      files[MAXINFILES];
};

Andy Heninger's avatar
Andy Heninger committed
//
//------------------------------------------------------------------------------
//
//  Global Data
//
//------------------------------------------------------------------------------
RunInfo         gRunInfo;
ThreadInfo      *gThreadInfo;

/** Grammar caching thread testing */
MemoryManager*  gpMemMgr = 0;
XMLGrammarPool* gp = 0;
// Routines which maybe helpful for debugging
static void printString(const XMLCh *str)
{
    char *s = XMLString::transcode(str);
    printf("%s", s);
    delete s;
}

#define CHARS_PER_LINE           40
#define BYTES_PER_LINE           16

/*
 * DumpLine: Dump out a buffer (address and length) to stderr.
 */
static void DumpLine(char* address, int length) {
    int i, c, charCount=0;
    if (length % 4) length += 4;
    fprintf(stderr, "%8.8p: ", address);
    for (i=0; i < length/4; ++i) {
        fprintf(stderr, "%8.8X ", ((int*)address)[i]);
        charCount += 9;
    }
    for (i=charCount; i < CHARS_PER_LINE; ++i) {
        putc(' ', stderr);
    }
    fprintf(stderr, "| ");
    for (i=0; i < length; ++i) {
        c = address[i];
        c = (isprint(c) ? c : '.');
        fprintf(stderr, "%c", c);
    }
    fprintf(stderr, "\n");
}

/*
 * dump: dump out a buffer (address and length) to stderr by dumping out
 *       a line at a time (DumpLine), until the buffer is written out.
 */

static void dump(void* generalAddress, int length) {
    int curr = 0;
    char* address = (char*) generalAddress;
    while (&address[curr] < &address[length-BYTES_PER_LINE]) {
        DumpLine(&address[curr], BYTES_PER_LINE);
        curr += BYTES_PER_LINE;
    }
    if (curr < length) {
        DumpLine(&address[curr], length-curr);
    }
    fflush(stderr);
}
Andy Heninger's avatar
Andy Heninger committed

//------------------------------------------------------------------------------
//
//  class ThreadParser   Bundles together a SAX parser and the SAX handlers
//                       and contains the API that the rest of this test
//                       program uses for creating parsers and doing parsing.
//
//                       Multiple instances of this class can operate concurrently
//                       in different threads.
//
//-------------------------------------------------------------------------------

class ThreadParser
{
public:
    class SAXHandler;
    class SAX2Handler;
    SAXHandler*     fSAXHandler;
    SAX2Handler*    fSAX2Handler;
    ErrorHandler*   fDOMErrorHandler;
    //  This is the API used by the rest of the test program
Andy Heninger's avatar
Andy Heninger committed
    ThreadParser();
    ~ThreadParser();

    int parse(int fileNum);           // Parse the specified file.  fileNum is an index
                                      //   into the gRunInfo.files array.
Andy Heninger's avatar
Andy Heninger committed
                                      //  return the XML checksum, or
                                      //  0 if a parse error occurred.
Andy Heninger's avatar
Andy Heninger committed
    int reCheck();                    // Try to compute the checksum again.
                                      //  for DOM, re-walk the tree.
                                      //  for SAX, can't do, just return previous value.

    void domPrint();                  //   including any children.  Default (no param)
Tinny Ng's avatar
Tinny Ng committed
                                       //   version dumps the entire document.
    void  addToCheckSum(const XMLCh *chars, XMLSize_t len=(XMLSize_t)-1);
    //  These are the SAX call-back functions that this class implements. Can be used
    //  for SAX and SAX2.
    void characters(const XMLCh* const chars, const XMLSize_t length) {
    void ignorableWhitespace(const XMLCh* const chars, const XMLSize_t length) {
    void warning(const SAXParseException& exc)     {
        fprintf(stderr, "*** Warning ");
    void error(const SAXParseException& exc)       {
        fprintf(stderr, "*** Error ");
    void fatalError(const SAXParseException& exc)  {
        fprintf(stderr, "***** Fatal error ");

    // Create a nested class that can inherit from HandlerBase
    // for SAX startElement callbacks.
    class SAXHandler :  public HandlerBase
    {
    public:
        ThreadParser* SAXInstance;

        void startElement(const XMLCh* const name, AttributeList& attributes);
    };

    // Create a nested class that can inherit from DefaultHandler
    // for SAX2 startElement callbacks.
    class SAX2Handler :  public DefaultHandler
    {
    public:
        ThreadParser* SAX2Instance;

        void startElement(const XMLCh* const uri,
                          const XMLCh* const localname,
                          const XMLCh* const qname,
                          const Attributes& attributes);
    };

private:
    int                                             fCheckSum;
    SAXParser*                                      fSAXParser;
    SAX2XMLReader*                                  fSAX2Parser;
    XercesDOMParser*                                fXercesDOMParser;
    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *    fDoc;
    ThreadParser(const ThreadParser &); // No copy constructor
    const ThreadParser & operator =(const ThreadParser &); // No assignment.

    void  domCheckSum(const DOMNode *);
};
Andy Heninger's avatar
Andy Heninger committed

//
//  ThreadParser constructor.  Invoked by the threads of the test program
//                              to create parsers.
//
ThreadParser::ThreadParser()
    fXercesDOMParser = 0;
Andy Heninger's avatar
Andy Heninger committed
    if (gRunInfo.dom) {
        // Set up to use a DOM parser
        /** Grammar caching thread testing */
        if (gp) {
            fXercesDOMParser = new XercesDOMParser(0, XMLPlatformUtils::fgMemoryManager, gp);
            fXercesDOMParser->cacheGrammarFromParse(true);
            fXercesDOMParser->useCachedGrammarInParse(true);
        else {
            fXercesDOMParser = new XercesDOMParser;
        }
        switch (gRunInfo.valScheme) {
            case SAXParser::Val_Never:
                fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Never);
                break;
            case SAXParser::Val_Auto:
                fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Auto);
                break;
            default: //SAXParser::Val_Always:
                fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Always);
                break;
        fXercesDOMParser->setDoSchema(gRunInfo.doSchema);
        fXercesDOMParser->setHandleMultipleImports (true);
        fXercesDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
        fXercesDOMParser->setDoNamespaces(gRunInfo.doNamespaces);
        fDOMErrorHandler = (ErrorHandler*) new HandlerBase();
        fXercesDOMParser->setErrorHandler(fDOMErrorHandler);
Tinny Ng's avatar
Tinny Ng committed
    }

    else if (gRunInfo.sax) {
        // Set up to use a SAX1 parser.
        /** Grammar caching thread testing */
        if (gp) {
            fSAXParser = new SAXParser(0, XMLPlatformUtils::fgMemoryManager, gp);
            fSAXParser->cacheGrammarFromParse(true);
            fSAXParser->useCachedGrammarInParse(true);
        else {
            fSAXParser = new SAXParser();
        }
        fSAXParser->setValidationScheme(gRunInfo.valScheme);
Tinny Ng's avatar
Tinny Ng committed
        fSAXParser->setDoSchema(gRunInfo.doSchema);
        fSAXParser->setHandleMultipleImports (true);
Tinny Ng's avatar
Tinny Ng committed
        fSAXParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
        fSAXParser->setDoNamespaces(gRunInfo.doNamespaces);
        fSAXHandler = new ThreadParser::SAXHandler();
        fSAXHandler->SAXInstance = this;
        fSAXParser->setDocumentHandler(fSAXHandler);
        fSAXParser->setErrorHandler(fSAXHandler);
Andy Heninger's avatar
Andy Heninger committed
    }
        // Set up to use a SAX2 parser.
        /** Grammar caching thread testing */
            fSAX2Parser = XMLReaderFactory::createXMLReader(gpMemMgr, gp);
            fSAX2Parser->setFeature(XMLUni::fgXercesCacheGrammarFromParse,true);
            fSAX2Parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse,true);
        }
        else {
            fSAX2Parser = XMLReaderFactory::createXMLReader();
        }
        fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpaces,(gRunInfo.doNamespaces));
        fSAX2Parser->setFeature(XMLUni::fgXercesSchema,(gRunInfo.doSchema));
        fSAX2Parser->setFeature(XMLUni::fgXercesHandleMultipleImports, true);
        fSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking,(gRunInfo.schemaFullChecking));

        switch (gRunInfo.valScheme) {
            case SAXParser::Val_Never:
                fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, false);
                break;
            case SAXParser::Val_Auto:
                fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
                fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, true);
                break;
            default: //SAXParser::Val_Always:
                fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
                fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, false);
                break;
        }

        fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes,(gRunInfo.doNamespacePrefixes));
        fSAX2Handler = new ThreadParser::SAX2Handler();
        fSAX2Handler->SAX2Instance = this;
        fSAX2Parser->setContentHandler(fSAX2Handler);
        fSAX2Parser->setErrorHandler(fSAX2Handler);
    }
}
Andy Heninger's avatar
Andy Heninger committed

ThreadParser::~ThreadParser()
{
     delete fXercesDOMParser;
Andy Heninger's avatar
Andy Heninger committed

//------------------------------------------------------------------------
//
//  parse   - This is the method that is invoked by the rest of
//            the test program to actually parse an XML file.
//
//------------------------------------------------------------------------
int ThreadParser::parse(int fileNum)
{
    MemBufInputSource *mbis = 0;
    InFileInfo        *fInfo = &gRunInfo.files[fileNum];
Tinny Ng's avatar
Tinny Ng committed
    bool              errors = false;
Andy Heninger's avatar
Andy Heninger committed

    fCheckSum = 0;

    if (gRunInfo.inMemory) {
        mbis = new  MemBufInputSource((const XMLByte *) fInfo->fileContent,
                                       fInfo->fileSize,
Tinny Ng's avatar
Tinny Ng committed
                                       fInfo->uFileName,
Andy Heninger's avatar
Andy Heninger committed
                                       false);
    }
Andy Heninger's avatar
Andy Heninger committed
    try
    {
        if (gRunInfo.dom) {
            // Do a DOM parse
            fXercesDOMParser->resetDocumentPool();
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
            if (gRunInfo.inMemory)
                fXercesDOMParser->parse(*mbis);
Andy Heninger's avatar
Andy Heninger committed
            else
                fXercesDOMParser->parse(fInfo->fileName);
            fDoc = fXercesDOMParser->getDocument();
            domCheckSum(fDoc);
Andy Heninger's avatar
Andy Heninger committed
        }
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
            if (gRunInfo.inMemory)
Andy Heninger's avatar
Andy Heninger committed
                fSAXParser->parse(*mbis);
            else
                fSAXParser->parse(fInfo->fileName);
        }
        else {
            // Do a SAX2 parse
            if (gRunInfo.inMemory)
                fSAX2Parser->parse(*mbis);
            else
                fSAX2Parser->parse(fInfo->fileName);
        }
    }
    catch (const OutOfMemoryException&)
    {
	    fprintf(stderr, " during parsing: %s\n OutOfMemoryException.\n", fInfo->fileName);
Andy Heninger's avatar
Andy Heninger committed
    }
    catch (const XMLException& e)
    {
Andy Heninger's avatar
Andy Heninger committed
        char *exceptionMessage = XMLString::transcode(e.getMessage());
        fprintf(stderr, " during parsing: %s\n Exception message is: %s\n",
Andy Heninger's avatar
Andy Heninger committed
            fInfo->fileName, exceptionMessage);
        XMLString::release(&exceptionMessage);
Tinny Ng's avatar
Tinny Ng committed
        errors = true;
    }
    catch (const DOMException& toCatch)
Tinny Ng's avatar
Tinny Ng committed
    {
        fprintf(stderr, " during parsing: %s\n DOMException code is: %i\n",
Tinny Ng's avatar
Tinny Ng committed
            fInfo->fileName, toCatch.code);
        errors = true;
    }
    catch (const SAXParseException& e)
    {
        char *exceptionMessage = XMLString::transcode(e.getMessage());
        fprintf(stderr, " during parsing: %s\n Exception message is: %s\n",
Tinny Ng's avatar
Tinny Ng committed
            fInfo->fileName, exceptionMessage);
        XMLString::release(&exceptionMessage);
Tinny Ng's avatar
Tinny Ng committed
        errors = true;
    }
    catch (...)
    {
        fprintf(stderr, "Unexpected exception during parsing\n");
        errors = true;
Andy Heninger's avatar
Andy Heninger committed
    }
Andy Heninger's avatar
Andy Heninger committed
    delete mbis;
Tinny Ng's avatar
Tinny Ng committed
        return 0;  // if errors occurred, return zero as if checksum = 0;
Andy Heninger's avatar
Andy Heninger committed
    return fCheckSum;
Andy Heninger's avatar
Andy Heninger committed


//
//  addToCheckSum - private function, used within ThreadParser in
//                  computing the checksum of the XML file.
//
//                  Unichar Strings to be added to the checksum
//                  can either be null terminated (omit len param, which
//                  will then default to -1), or provide an explicit
//                  length.
//
void ThreadParser::addToCheckSum(const XMLCh *chars, XMLSize_t len)
Andy Heninger's avatar
Andy Heninger committed
{
    if (len == (XMLSize_t)-1)
Andy Heninger's avatar
Andy Heninger committed
    {
        // Null terminated string.
        while (*chars != 0)
        {
            fCheckSum = fCheckSum*5 + *chars;
            chars++;
        }
    }
    else
    {
        // String with character count.
        XMLSize_t i;
Andy Heninger's avatar
Andy Heninger committed
        for (i=0; i<len; i++)
            fCheckSum = fCheckSum*5 + chars[i];
    }
// startElement - our SAX handler callback function for startElement.
//                Update the document checksum with the element name
Andy Heninger's avatar
Andy Heninger committed
//                and any attribute names and values.
//
 void ThreadParser::SAXHandler::startElement(const XMLCh *const name, AttributeList &attributes)
Andy Heninger's avatar
Andy Heninger committed
{
    XMLSize_t n = attributes.getLength();
    XMLSize_t i;
Andy Heninger's avatar
Andy Heninger committed
    for (i=0; i<n; i++)
    {
        const XMLCh *attNam = attributes.getName(i);
Andy Heninger's avatar
Andy Heninger committed
        const XMLCh *attVal = attributes.getValue(i);
//
// startElement - our SAX2 handler callback function for startElement.
//                Update the document checksum with the element name
//                and any attribute names and values.
//

void ThreadParser::SAX2Handler::startElement(const XMLCh *const /*uri*/,
                              const Attributes& attributes)
{
    SAX2Instance->addToCheckSum(localname);

    XMLSize_t n = attributes.getLength();
    XMLSize_t i;
    for (i=0; i<n; i++)
    {
        const XMLCh *attNam = attributes.getQName(i);
        SAX2Instance->addToCheckSum(attNam);
        const XMLCh *attVal = attributes.getValue(i);
        SAX2Instance->addToCheckSum(attVal);
    }
}
Andy Heninger's avatar
Andy Heninger committed

//
// domCheckSum  -  Compute the check sum for a DOM node.
//                 Works recursively - initially called with a document node.
//
void ThreadParser::domCheckSum(const DOMNode *node)
Tinny Ng's avatar
Tinny Ng committed
{
    const XMLCh        *s;
    DOMNode          *child;
    DOMNamedNodeMap  *attributes;
Tinny Ng's avatar
Tinny Ng committed

    switch (node->getNodeType() )
    {
    case DOMNode::ELEMENT_NODE:
Tinny Ng's avatar
Tinny Ng committed
        {
            s = node->getNodeName();   // the element name

            attributes = node->getAttributes();  // Element's attributes
            XMLSize_t numAttributes = attributes->getLength();
            XMLSize_t i;
Tinny Ng's avatar
Tinny Ng committed
            for (i=0; i<numAttributes; i++)
                domCheckSum(attributes->item(i));
Tinny Ng's avatar
Tinny Ng committed

            addToCheckSum(s);          // Content and Children
            for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
    case DOMNode::ATTRIBUTE_NODE:
Tinny Ng's avatar
Tinny Ng committed
        {
            s = node->getNodeName();  // The attribute name
            addToCheckSum(s);
            s = node->getNodeValue();  // The attribute value
            if (s != 0)
                addToCheckSum(s);
            break;
        }

    case DOMNode::TEXT_NODE:
    case DOMNode::CDATA_SECTION_NODE:
Tinny Ng's avatar
Tinny Ng committed
        {
            s = node->getNodeValue();
            addToCheckSum(s);
            break;
        }

    case DOMNode::ENTITY_REFERENCE_NODE:
    case DOMNode::DOCUMENT_NODE:
Tinny Ng's avatar
Tinny Ng committed
        {
            // For entity references and the document, nothing is dirctly
            //  added to the checksum, but we do want to process the chidren nodes.
            //
            for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
Tinny Ng's avatar
Tinny Ng committed
            break;
        }
    case DOMNode::ENTITY_NODE:
    case DOMNode::PROCESSING_INSTRUCTION_NODE:
    case DOMNode::COMMENT_NODE:
    case DOMNode::DOCUMENT_TYPE_NODE:
    case DOMNode::DOCUMENT_FRAGMENT_NODE:
    case DOMNode::NOTATION_NODE:
        break;
Andy Heninger's avatar
Andy Heninger committed
//
// Recompute the checksum.  Meaningful only for DOM, will tell us whether
//  a failure is transient, or whether the DOM data is permanently corrupted.
//
int ThreadParser::reCheck()
{
    if (gRunInfo.dom) {
        fCheckSum = 0;
Tinny Ng's avatar
Tinny Ng committed
    }
Andy Heninger's avatar
Andy Heninger committed
    return fCheckSum;
}

//
// domPrint  -  Dump the contents of a DOM node.
Andy Heninger's avatar
Andy Heninger committed
//              For debugging failures, when all else fails.
//                 Works recursively - initially called with a document node.
//
void ThreadParser::domPrint()
{
    printf("Begin DOMPrint ...\n");
Andy Heninger's avatar
Andy Heninger committed
    if (gRunInfo.dom)
    {
        try
        {
            XMLCh tempStr[100];
            XMLString::transcode("LS", tempStr, 99);
            DOMImplementation *impl          = DOMImplementationRegistry::getDOMImplementation(tempStr);
            DOMLSSerializer   *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
            DOMLSOutput       *theOutput     = ((DOMImplementationLS*)impl)->createLSOutput();
            XMLFormatTarget   *myFormTarget  = new StdOutFormatTarget();
            DOMNode           *doc           = fXercesDOMParser->getDocument();
            theSerializer->write(doc,theOutput);
            delete myFormTarget;
            theSerializer->release();
            theOutput->release();
        }
        catch (...)
        {
            // do nothing
        }
    }
    printf("End DOMPrint\n");
Andy Heninger's avatar
Andy Heninger committed
//----------------------------------------------------------------------
//
//   parseCommandLine   Read through the command line, and save all
//                      of the options in the gRunInfo struct.
//
//                      Display the usage message if the command line
//                      is no good.
//
//                      Probably ought to be a member function of RunInfo.
//
//----------------------------------------------------------------------

void parseCommandLine(int argc, char **argv)
{
    gRunInfo.doGrammarCaching = false;
Andy Heninger's avatar
Andy Heninger committed
    gRunInfo.quiet = false;               // Set up defaults for run.
    gRunInfo.verbose = false;
    gRunInfo.stopNow = false;
Andy Heninger's avatar
Andy Heninger committed
    gRunInfo.dom = false;
Andy Heninger's avatar
Andy Heninger committed
    gRunInfo.reuseParser = false;
Andy Heninger's avatar
Andy Heninger committed
    gRunInfo.dumpOnErr = false;
    gRunInfo.doSchema = false;
    gRunInfo.schemaFullChecking = false;
    gRunInfo.doNamespaces = false;
    gRunInfo.doInitialParse = false;
    gRunInfo.doNamespacePrefixes = false;

    gRunInfo.valScheme = SAXParser::Val_Auto;
    gRunInfo.numThreads = 2;
Andy Heninger's avatar
Andy Heninger committed
    gRunInfo.totalTime = 0;
    gRunInfo.numInputFiles = 0;
Andy Heninger's avatar
Andy Heninger committed
    try             // Use exceptions for command line syntax errors.
    {
        int argnum = 1;
Andy Heninger's avatar
Andy Heninger committed
            if (strcmp(argv[argnum], "-quiet") == 0)
                gRunInfo.quiet = true;
            else if (strcmp(argv[argnum], "-verbose") == 0)
                gRunInfo.verbose = true;
            else if (strncmp(argv[argnum], "-v=", 3) == 0) {
                const char* const parm = &argv[argnum][3];
                if (!strcmp(parm, "never"))
                    gRunInfo.valScheme = SAXParser::Val_Never;
                else if (!strcmp(parm, "auto"))
                    gRunInfo.valScheme = SAXParser::Val_Auto;
                else if (!strcmp(parm, "always"))
                    gRunInfo.valScheme = SAXParser::Val_Always;
                else {
                    fprintf(stderr, "Unrecognized -v option \"%s\"\n", parm);
                    throw 1;
                }
            }
            else if (strcmp(argv[argnum], "-v") == 0) {
                fprintf(stderr, "Please note the -v option has been changed to -v=[always | never | auto]\n");
                fprintf(stderr, "ThreadTest will continue with -v=always\n");
                gRunInfo.valScheme = SAXParser::Val_Always;
            }
Tinny Ng's avatar
Tinny Ng committed
            else if (strcmp(argv[argnum], "-s") == 0)
                gRunInfo.doSchema = true;
            else if (strcmp(argv[argnum], "-f") == 0)
                gRunInfo.schemaFullChecking = true;
            else if (strcmp(argv[argnum], "-n") == 0)
                gRunInfo.doNamespaces = true;
                gRunInfo.doNamespacePrefixes = true;
Tinny Ng's avatar
Tinny Ng committed
            else if (!strncmp(argv[argnum], "-parser=", 8)) {
                const char* const parm = &argv[argnum][8];
Tinny Ng's avatar
Tinny Ng committed
                if (!strcmp(parm, "dom")) {
                    gRunInfo.dom = true;
Tinny Ng's avatar
Tinny Ng committed
                }
                else if (!strcmp(parm, "sax")) {
                    gRunInfo.dom = false;
Tinny Ng's avatar
Tinny Ng committed
                }
                else if (!strcmp(parm, "sax2")) {
                    gRunInfo.dom = false;
                    gRunInfo.sax = false;
                    fprintf(stderr, "Unrecognized -parser option \"%s\"\n", parm);
Tinny Ng's avatar
Tinny Ng committed
                    throw 1;
Tinny Ng's avatar
Tinny Ng committed
            }
            else if (strcmp(argv[argnum], "-init") == 0)
                gRunInfo.doInitialParse = true;
Andy Heninger's avatar
Andy Heninger committed
            else if (strcmp(argv[argnum], "-reuse") == 0)
                gRunInfo.reuseParser = true;
            else if (strcmp(argv[argnum], "-dump") == 0)
                gRunInfo.dumpOnErr = true;
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
            else if (strcmp(argv[argnum], "-mem") == 0)
            else if (strcmp(argv[argnum], "-threads") == 0) {
Andy Heninger's avatar
Andy Heninger committed
                ++argnum;
                if (argnum >= argc) {
                    fprintf(stderr, "Invalid -threads option (missing # of threads)\n");
Andy Heninger's avatar
Andy Heninger committed
                    throw 1;
Andy Heninger's avatar
Andy Heninger committed
                gRunInfo.numThreads = atoi(argv[argnum]);
                if (gRunInfo.numThreads < 0) {
                    fprintf(stderr, "Invalid -threads option (negative # of threads)\n");
Andy Heninger's avatar
Andy Heninger committed
                    throw 1;
Andy Heninger's avatar
Andy Heninger committed
            }
            else if (strcmp(argv[argnum], "-time") == 0) {
Andy Heninger's avatar
Andy Heninger committed
                ++argnum;
                if (argnum >= argc) {
                    fprintf(stderr, "Invalid -time option (missing time value)\n");
Andy Heninger's avatar
Andy Heninger committed
                    throw 1;
Andy Heninger's avatar
Andy Heninger committed
                gRunInfo.totalTime = atoi(argv[argnum]);
                if (gRunInfo.totalTime < 1) {
                    fprintf(stderr, "Invalid -time option (time value < 1)\n");
Andy Heninger's avatar
Andy Heninger committed
                    throw 1;
                gRunInfo.doGrammarCaching = true;
            else if (strcmp(argv[argnum], "-parses") == 0) {
                ++argnum;
                if (argnum >= argc) {
                    fprintf(stderr, "Invalid -parses option (missing # of parses)\n");
                    throw 1;
                }
                int temp = atoi(argv[argnum]);
                if (temp < 0) {
                    fprintf(stderr, "Invalid -parses option (negative # of parses)\n");
                    throw 1;
                }
                gRunInfo.numParses = temp;
Andy Heninger's avatar
Andy Heninger committed
            }
Andy Heninger's avatar
Andy Heninger committed
                fprintf(stderr, "Unrecognized command line option.  Scanning \"%s\"\n",
                    argv[argnum]);
                throw 1;
            }
Andy Heninger's avatar
Andy Heninger committed
                gRunInfo.numInputFiles++;
                if (gRunInfo.numInputFiles >= MAXINFILES) {
Andy Heninger's avatar
Andy Heninger committed
                    fprintf(stderr, "Too many input files.  Limit is %d\n", MAXINFILES);
                    throw 1;
                }
                gRunInfo.files[gRunInfo.numInputFiles-1].fileName = argv[argnum];
            }
Unknown (aruna1)'s avatar
Unknown (aruna1) committed
            argnum++;
Andy Heninger's avatar
Andy Heninger committed
        }
Andy Heninger's avatar
Andy Heninger committed
        // We've made it through the command line.
        // Verify that at least one input file to be parsed was specified.
        if (gRunInfo.numInputFiles == 0) {
Andy Heninger's avatar
Andy Heninger committed
            fprintf(stderr, "No input XML file specified on command line.\n");
            throw 1;
        };
        if (gRunInfo.numParses && gRunInfo.totalTime) {
            fprintf(stderr, "Both -parses nnn and -time nnn were specified. Ignoring -time nnn.\n");
        }
Andy Heninger's avatar
Andy Heninger committed
    }
    catch (int)
    {
        fprintf(stderr, "usage:  ThreadTest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n"
            "     -v=xxx         Validation scheme [always | never | auto].  Default is AUTO.\n"
Tinny Ng's avatar
Tinny Ng committed
            "     -n             Enable namespace processing. Defaults to off.\n"
            "     -s             Enable schema processing. Defaults to off.\n"
            "     -f             Enable full schema constraint checking. Defaults to off.\n"
            "     -parser=xxx    Parser Type [dom | sax | sax2].  Default is SAX (SAX1).\n"
            "     -p             Enable namespace prefixes. Defaults to off.\n"
            "                    (Only used with -parser=sax2, ignored otherwise.)\n"
Tinny Ng's avatar
Tinny Ng committed
            "     -quiet         Suppress periodic status display.\n"
            "     -verbose       Display extra messages.\n"
Andy Heninger's avatar
Andy Heninger committed
            "     -reuse         Retain and reuse parser.  Default creates new for each parse.\n"
Tinny Ng's avatar
Tinny Ng committed
            "     -threads nnn   Number of threads.  Default is 2.\n"
Andy Heninger's avatar
Andy Heninger committed
            "     -time nnn      Total time to run, in seconds.  Default is forever.\n"
            "     -parses nnn    Run for nnn parses instead of time.  Default is to use time\n"
Andy Heninger's avatar
Andy Heninger committed
            "     -dump          Dump DOM tree on error.\n"
            "     -mem           Read files into memory once only, and parse them from there.\n"
            "     -gc            Enable grammar caching (i.e. grammar cached and used in subsequent parses). Defaults to off.\n"
            "     -init          Perform an initial parse of the file(s) before starting up the individual threads.\n\n"
Andy Heninger's avatar
Andy Heninger committed
            );
        exit(1);
    }
Andy Heninger's avatar
Andy Heninger committed


//---------------------------------------------------------------------------
//