ThreadTest.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:35k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: ThreadTest.cpp,v 1.30 2003/03/13 22:13:28 tng Exp $
  58.  *
  59.  * @author Andy Heninger, IBM
  60.  */
  61. #include <stdlib.h>
  62. #include <stdio.h>
  63. #include <string.h>
  64. #include <xercesc/parsers/SAXParser.hpp>
  65. #include <xercesc/parsers/XercesDOMParser.hpp>
  66. #include <xercesc/util/PlatformUtils.hpp>
  67. #include <xercesc/sax/HandlerBase.hpp>
  68. #include <xercesc/framework/MemBufInputSource.hpp>
  69. #include <xercesc/dom/DOM.hpp>
  70. #include <xercesc/framework/StdOutFormatTarget.hpp>
  71. void clearFileInfoMemory();
  72. //------------------------------------------------------------------------------
  73. //
  74. //   Windows specific code for starting threads
  75. //
  76. //------------------------------------------------------------------------------
  77. #ifdef PLATFORM_WIN32
  78. #include "Windows.h"
  79. #include "process.h"
  80. typedef DWORD (WINAPI *ThreadFunc)(void *);
  81. class ThreadFuncs           // This class isolates OS dependent threading
  82. {                           //   functions from the rest of ThreadTest program.
  83. public:
  84.     static void Sleep(int millis) {::Sleep(millis);};
  85.     static void startThread(ThreadFunc, void *param);
  86. };
  87. void ThreadFuncs::startThread(ThreadFunc func, void *param)
  88. {
  89.     HANDLE  tHandle;
  90.     DWORD   threadID;
  91.     tHandle = CreateThread(0,          // Security Attributes,
  92.                            0x10000,    // Stack Size,
  93.                            func,       // Starting Address.
  94.                            param,      // Parmeters
  95.                            0,          // Creation Flags,
  96.                            &threadID); // Thread ID (Can not be null on 95/98)
  97.     if (tHandle == 0)
  98.     {
  99.         fprintf(stderr, "Error starting thread.  Errno = %dn", errno);
  100.         clearFileInfoMemory();
  101.         exit(-1);
  102.     }
  103.     // Set the priority of the working threads low, so that the UI of the running system will
  104.     //   remain responsive.
  105.     SetThreadPriority(tHandle, THREAD_PRIORITY_IDLE);
  106. }
  107. #elif defined (AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined (OS390) || defined(FREEBSD) || defined(__CYGWIN__) || defined(__QNXNTO__)
  108. #include <pthread.h>
  109. #include <unistd.h>
  110. #include <errno.h>
  111. //------------------------------------------------------------------------------
  112. //
  113. //   UNIX specific code for starting threads
  114. //
  115. //------------------------------------------------------------------------------
  116. extern "C" {
  117. typedef void (*ThreadFunc)(void *);
  118. typedef void *(*pthreadfunc)(void *);
  119. class ThreadFuncs           // This class isolates OS dependent threading
  120. {                           //   functions from the rest of ThreadTest program.
  121. public:
  122.     static void Sleep(int millis);
  123.     static void startThread(ThreadFunc, void *param);
  124. };
  125. void ThreadFuncs::Sleep(int millis)
  126. {
  127.    int seconds = millis/1000;
  128.    if (seconds <= 0) seconds = 1;
  129. #if defined(SOLARIS)
  130.    // somehow the sleep hangs on Solaris
  131.    // so ignore the call
  132. #else
  133.    ::sleep(seconds);
  134. #endif
  135. }
  136. void ThreadFuncs::startThread(ThreadFunc func, void *param)
  137. {
  138.     unsigned long x;
  139.     pthread_t tId;
  140.     //thread_t tId;
  141. #if defined(_HP_UX) && defined(XML_USE_DCE)
  142.     x = pthread_create( &tId, pthread_attr_default,  (pthreadfunc)func,  param);
  143. #else
  144.     pthread_attr_t attr;
  145.     pthread_attr_init(&attr);
  146.     x = pthread_create( &tId, &attr,  (pthreadfunc)func,  param);
  147. #endif
  148.     if (x == -1)
  149.     {
  150.         fprintf(stderr, "Error starting thread.  Errno = %dn", errno);
  151.         clearFileInfoMemory();
  152.         exit(-1);
  153.     }
  154. }
  155. }
  156. #else
  157. #error This platform is not supported
  158. #endif
  159. //------------------------------------------------------------------------------
  160. //
  161. //  struct InFileInfo   One of these structs will be set up for each file listed
  162. //                      on the command line.  Once set, the data is unchanging
  163. //                      and can safely be referenced by the test threads without
  164. //                      use of synchronization.
  165. //
  166. //------------------------------------------------------------------------------
  167. struct InFileInfo
  168. {
  169.     char    *fileName;
  170.     XMLCh   *uFileName;      // When doing an in-memory parse, avoid transcoding file name
  171.                              //    each time through.
  172.     char    *fileContent;    // If doing an in-memory parse, this field points
  173.                              //   to an allocated string containing the entire file
  174.                              //   contents.  Otherwise it's 0.
  175.     size_t  fileSize;        // The file length.  Only initialized when doing
  176.                              //   an in-memory test.
  177.     int     checkSum;        // The XML checksum.  Set up by the main thread for
  178.                              //   each file before the worker threads are started.
  179. };
  180. //------------------------------------------------------------------------------
  181. //
  182. //  struct runInfo     Holds the info extracted from the command line.
  183. //                     There is only one of these, and it is static, and
  184. //                     unchanging once the command line has been parsed.
  185. //                     During the test, the threads will access this info without
  186. //                     any synchronization.
  187. //
  188. //------------------------------------------------------------------------------
  189. const int MAXINFILES = 25;
  190. struct RunInfo
  191. {
  192.     bool        quiet;
  193.     bool        verbose;
  194.     bool        stopNow;
  195.     int         numThreads;
  196.     bool        validating;
  197.     bool        dom;
  198.     bool        reuseParser;
  199.     bool        inMemory;
  200.     bool        dumpOnErr;
  201.     bool        doSchema;
  202.     bool        schemaFullChecking;
  203.     bool        doNamespaces;
  204.     int         totalTime;
  205.     int         numInputFiles;
  206.     InFileInfo  files[MAXINFILES];
  207. };
  208. //------------------------------------------------------------------------------
  209. //
  210. //  struct threadInfo  Holds information specific to an individual thread.
  211. //                     One of these is set up for each thread in the test.
  212. //                     The main program monitors the threads by looking
  213. //                     at the status stored in these structs.
  214. //
  215. //------------------------------------------------------------------------------
  216. struct ThreadInfo
  217. {
  218.     bool    fHeartBeat;            // Set true by the thread each time it finishes
  219.                                    //   parsing a file.
  220.     bool    fInProgress;           // Set to false by the thread when parse in progress
  221.     unsigned int     fParses;      // Number of parses completed.
  222.     int              fThreadNum;   // Identifying number for this thread.
  223.     ThreadInfo() {
  224.         fHeartBeat = false;
  225.         fInProgress = false;
  226.         fParses = 0;
  227.         fThreadNum = -1;
  228.     }
  229. };
  230. //
  231. //------------------------------------------------------------------------------
  232. //
  233. //  Global Data
  234. //
  235. //------------------------------------------------------------------------------
  236. RunInfo         gRunInfo;
  237. ThreadInfo      *gThreadInfo;
  238. XERCES_CPP_NAMESPACE_USE
  239. //------------------------------------------------------------------------------
  240. //
  241. //  class ThreadParser   Bundles together a SAX parser and the SAX handlers
  242. //                       and contains the API that the rest of this test
  243. //                       program uses for creating parsers and doing parsing.
  244. //
  245. //                       Multiple instances of this class can operate concurrently
  246. //                       in different threads.
  247. //
  248. //-------------------------------------------------------------------------------
  249. class ThreadParser: public HandlerBase
  250. {
  251. private:
  252.     int           fCheckSum;
  253.     SAXParser*    fSAXParser;
  254.     XercesDOMParser*    fXercesDOMParser;
  255.     XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * fDoc;
  256. public:                               //  This is the API used by the rest of the test program
  257.     ThreadParser();
  258.     ~ThreadParser();
  259.     int parse(int fileNum);           // Parse the specified file.  fileNum is an index
  260.                                       //   into the gRunInfo.files array.
  261.                                       //  return the XML checksum, or
  262.                                       //  0 if a parse error occurred.
  263.     int reCheck();                    // Try to compute the checksum again.
  264.                                       //  for DOM, re-walk the tree.
  265.                                       //  for SAX, can't do, just return previous value.
  266.     void domPrint();                  //   including any children.  Default (no param)
  267.                                        //   version dumps the entire document.
  268. private:
  269.     ThreadParser(const ThreadParser &); // No copy constructor
  270.     const ThreadParser & operator =(const ThreadParser &); // No assignment.
  271.     void  addToCheckSum(const XMLCh *chars, int len=-1);
  272.     void  domCheckSum(const DOMNode *);
  273. public:                               // Not really public,
  274.                                       //  These are the SAX call-back functions
  275.                                       //  that this class implements.
  276.     void startElement(const XMLCh* const name, AttributeList& attributes);
  277.     void characters(const XMLCh* const chars, const unsigned int length) {
  278.         addToCheckSum(chars, length);};
  279.     void ignorableWhitespace(const XMLCh* const chars, const unsigned int length) {
  280.         addToCheckSum(chars, length);};
  281.     void resetDocument() {};
  282.     void warning(const SAXParseException& exception)     {
  283.         fprintf(stderr, "*** Warning ");
  284.         throw exception;};
  285.     void error(const SAXParseException& exception)       {
  286.         fprintf(stderr, "*** Error ");
  287.         throw exception;};
  288.     void fatalError(const SAXParseException& exception)  {
  289.         fprintf(stderr, "***** Fatal error ");
  290.         throw exception;};
  291. };
  292. //
  293. //  ThreadParser constructor.  Invoked by the threads of the test program
  294. //                              to create parsers.
  295. //
  296. ThreadParser::ThreadParser()
  297. {
  298.     fSAXParser = 0;
  299.     fXercesDOMParser = 0;
  300.     fDoc       = 0;
  301.     if (gRunInfo.dom) {
  302.         // Set up to use a DOM parser
  303.         fXercesDOMParser = new XercesDOMParser;
  304.         fXercesDOMParser->setDoValidation(gRunInfo.validating);
  305.         fXercesDOMParser->setDoSchema(gRunInfo.doSchema);
  306.         fXercesDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
  307.         fXercesDOMParser->setDoNamespaces(gRunInfo.doNamespaces);
  308.         fXercesDOMParser->setErrorHandler(this);
  309.     }
  310.     else
  311.     {
  312.         // Set up to use a SAX parser.
  313.         fSAXParser = new SAXParser;
  314.         fSAXParser->setDoValidation(gRunInfo.validating);
  315.         fSAXParser->setDoSchema(gRunInfo.doSchema);
  316.         fSAXParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking);
  317.         fSAXParser->setDoNamespaces(gRunInfo.doNamespaces);
  318.         fSAXParser->setDocumentHandler(this);
  319.         fSAXParser->setErrorHandler(this);
  320.     }
  321. }
  322. ThreadParser::~ThreadParser()
  323. {
  324.      delete fSAXParser;
  325.      delete fXercesDOMParser;
  326. }
  327. //------------------------------------------------------------------------
  328. //
  329. //  parse   - This is the method that is invoked by the rest of
  330. //            the test program to actually parse an XML file.
  331. //
  332. //------------------------------------------------------------------------
  333. int ThreadParser::parse(int fileNum)
  334. {
  335.     MemBufInputSource *mbis = 0;
  336.     InFileInfo        *fInfo = &gRunInfo.files[fileNum];
  337.     bool              errors = false;
  338.     fCheckSum = 0;
  339.     if (gRunInfo.inMemory) {
  340.         mbis = new  MemBufInputSource((const XMLByte *) fInfo->fileContent,
  341.                                        fInfo->fileSize,
  342.                                        fInfo->uFileName,
  343.                                        false);
  344.     }
  345.     try
  346.     {
  347.         if (gRunInfo.dom) {
  348.             // Do a DOM parse
  349.             if (gRunInfo.inMemory)
  350.                 fXercesDOMParser->parse(*mbis);
  351.             else
  352.                 fXercesDOMParser->parse(fInfo->fileName);
  353.             XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc = fXercesDOMParser->getDocument();
  354.             domCheckSum(doc);
  355.         }
  356.         else
  357.         {
  358.             // Do a SAX parse
  359.             if (gRunInfo.inMemory)
  360.                 fSAXParser->parse(*mbis);
  361.             else
  362.                 fSAXParser->parse(fInfo->fileName);
  363.         }
  364.     }
  365.     catch (const XMLException& e)
  366.     {
  367.         char *exceptionMessage = XMLString::transcode(e.getMessage());
  368.         fprintf(stderr, " during parsing: %s n Exception message is: %s n",
  369.             fInfo->fileName, exceptionMessage);
  370.         XMLString::release(&exceptionMessage);
  371.         errors = true;
  372.     }
  373.     catch (const DOMException& toCatch)
  374.     {
  375.         fprintf(stderr, " during parsing: %s n DOMException code is: %i n",
  376.             fInfo->fileName, toCatch.code);
  377.         errors = true;
  378.     }
  379.     catch (const SAXParseException& e)
  380.     {
  381.         char *exceptionMessage = XMLString::transcode(e.getMessage());
  382.         fprintf(stderr, " during parsing: %s n Exception message is: %s n",
  383.             fInfo->fileName, exceptionMessage);
  384.         XMLString::release(&exceptionMessage);
  385.         errors = true;
  386.     }
  387.     catch (...)
  388.     {
  389.         fprintf(stderr, "Unexpected exception during parsingn");
  390.         errors = true;
  391.     }
  392.     delete mbis;
  393.     if (errors)
  394.         return 0;  // if errors occurred, return zero as if checksum = 0;
  395.     return fCheckSum;
  396. }
  397. //
  398. //  addToCheckSum - private function, used within ThreadParser in
  399. //                  computing the checksum of the XML file.
  400. //
  401. //                  Unichar Strings to be added to the checksum
  402. //                  can either be null terminated (omit len param, which
  403. //                  will then default to -1), or provide an explicit
  404. //                  length.
  405. //
  406. void ThreadParser::addToCheckSum(const XMLCh *chars, int len)
  407. {
  408.     if (len == -1)
  409.     {
  410.         // Null terminated string.
  411.         while (*chars != 0)
  412.         {
  413.             fCheckSum = fCheckSum*5 + *chars;
  414.             chars++;
  415.         }
  416.     }
  417.     else
  418.     {
  419.         // String with character count.
  420.         int i;
  421.         for (i=0; i<len; i++)
  422.             fCheckSum = fCheckSum*5 + chars[i];
  423.     }
  424. }
  425. //
  426. // startElement - our SAX handler callback function for element starts.
  427. //                update the document checksum with the element name
  428. //                and any attribute names and values.
  429. //
  430. void ThreadParser::startElement(const XMLCh *const name, AttributeList &attributes)
  431. {
  432.     addToCheckSum(name);
  433.     int n = attributes.getLength();
  434.     int i;
  435.     for (i=0; i<n; i++)
  436.     {
  437.         const XMLCh *attNam = attributes.getName(i);
  438.         addToCheckSum(attNam);
  439.         const XMLCh *attVal = attributes.getValue(i);
  440.         addToCheckSum(attVal);
  441.     }
  442. }
  443. //
  444. // domCheckSum  -  Compute the check sum for a DOM node.
  445. //                 Works recursively - initially called with a document node.
  446. //
  447. void ThreadParser::domCheckSum(const DOMNode *node)
  448. {
  449.     const XMLCh        *s;
  450.     DOMNode          *child;
  451.     DOMNamedNodeMap  *attributes;
  452.     switch (node->getNodeType() )
  453.     {
  454.     case DOMNode::ELEMENT_NODE:
  455.         {
  456.             s = node->getNodeName();   // the element name
  457.             attributes = node->getAttributes();  // Element's attributes
  458.             int numAttributes = attributes->getLength();
  459.             int i;
  460.             for (i=0; i<numAttributes; i++)
  461.                 domCheckSum(attributes->item(i));
  462.             addToCheckSum(s);          // Content and Children
  463.             for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
  464.                 domCheckSum(child);
  465.             break;
  466.         }
  467.     case DOMNode::ATTRIBUTE_NODE:
  468.         {
  469.             s = node->getNodeName();  // The attribute name
  470.             addToCheckSum(s);
  471.             s = node->getNodeValue();  // The attribute value
  472.             if (s != 0)
  473.                 addToCheckSum(s);
  474.             break;
  475.         }
  476.     case DOMNode::TEXT_NODE:
  477.     case DOMNode::CDATA_SECTION_NODE:
  478.         {
  479.             s = node->getNodeValue();
  480.             addToCheckSum(s);
  481.             break;
  482.         }
  483.     case DOMNode::ENTITY_REFERENCE_NODE:
  484.     case DOMNode::DOCUMENT_NODE:
  485.         {
  486.             // For entity references and the document, nothing is dirctly
  487.             //  added to the checksum, but we do want to process the chidren nodes.
  488.             //
  489.             for (child=node->getFirstChild(); child!=0; child=child->getNextSibling())
  490.                 domCheckSum(child);
  491.             break;
  492.         }
  493.     }
  494. }
  495. //
  496. // Recompute the checksum.  Meaningful only for DOM, will tell us whether
  497. //  a failure is transient, or whether the DOM data is permanently corrupted.
  498. //
  499. int ThreadParser::reCheck()
  500. {
  501.     if (gRunInfo.dom) {
  502.         fCheckSum = 0;
  503.         domCheckSum(fDoc);
  504.     }
  505.     return fCheckSum;
  506. }
  507. //
  508. // domPrint  -  Dump the contents of a DOM node.
  509. //              For debugging failures, when all else fails.
  510. //                 Works recursively - initially called with a document node.
  511. //
  512. void ThreadParser::domPrint()
  513. {
  514.     printf("Begin DOMPrint ...n");
  515.     if (gRunInfo.dom)
  516.     {
  517.         try
  518.         {
  519.             XMLCh tempStr[100];
  520.             XMLString::transcode("LS", tempStr, 99);
  521.             DOMImplementation *impl          = DOMImplementationRegistry::getDOMImplementation(tempStr);
  522.             DOMWriter         *theSerializer = ((DOMImplementationLS*)impl)->createDOMWriter();
  523.             XMLFormatTarget   *myFormTarget  = new StdOutFormatTarget();
  524.             DOMNode           *doc           = fXercesDOMParser->getDocument();
  525.             theSerializer->writeNode(myFormTarget, *doc);
  526.             delete theSerializer;
  527.         }
  528.         catch (...)
  529.         {
  530.             // do nothing
  531.         }
  532.     }
  533.     printf("End DOMPrintn");
  534. }
  535. static void printString(const XMLCh *str)
  536. {
  537.     char *s = XMLString::transcode(str);
  538.     printf("%s", s);
  539.     delete s;
  540. }
  541. //----------------------------------------------------------------------
  542. //
  543. //   parseCommandLine   Read through the command line, and save all
  544. //                      of the options in the gRunInfo struct.
  545. //
  546. //                      Display the usage message if the command line
  547. //                      is no good.
  548. //
  549. //                      Probably ought to be a member function of RunInfo.
  550. //
  551. //----------------------------------------------------------------------
  552. void parseCommandLine(int argc, char **argv)
  553. {
  554.     gRunInfo.quiet = false;               // Set up defaults for run.
  555.     gRunInfo.verbose = false;
  556.     gRunInfo.numThreads = 2;
  557.     gRunInfo.validating = false;
  558.     gRunInfo.doSchema = false;
  559.     gRunInfo.schemaFullChecking = false;
  560.     gRunInfo.doNamespaces = false;
  561.     gRunInfo.dom = false;
  562.     gRunInfo.reuseParser = false;
  563.     gRunInfo.inMemory = false;
  564.     gRunInfo.dumpOnErr = false;
  565.     gRunInfo.totalTime = 0;
  566.     gRunInfo.numInputFiles = 0;
  567.     try             // Use exceptions for command line syntax errors.
  568.     {
  569.         int argnum = 1;
  570.         while (argnum < argc)
  571.         {
  572.             if (strcmp(argv[argnum], "-quiet") == 0)
  573.                 gRunInfo.quiet = true;
  574.             else if (strcmp(argv[argnum], "-verbose") == 0)
  575.                 gRunInfo.verbose = true;
  576.             else if (strcmp(argv[argnum], "-v") == 0)
  577.                 gRunInfo.validating = true;
  578.             else if (strcmp(argv[argnum], "-s") == 0)
  579.                 gRunInfo.doSchema = true;
  580.             else if (strcmp(argv[argnum], "-f") == 0)
  581.                 gRunInfo.schemaFullChecking = true;
  582.             else if (strcmp(argv[argnum], "-n") == 0)
  583.                 gRunInfo.doNamespaces = true;
  584.             else if (!strncmp(argv[argnum], "-parser=", 8)) {
  585.                 const char* const parm = &argv[argnum][8];
  586.                 if (!strcmp(parm, "dom")) {
  587.                     gRunInfo.dom = true;
  588.                 }
  589.                 else if (!strcmp(parm, "sax")) {
  590.                     gRunInfo.dom = false;
  591.                 }
  592.                 else
  593.                     throw 1;
  594.             }
  595.             else if (strcmp(argv[argnum], "-reuse") == 0)
  596.                 gRunInfo.reuseParser = true;
  597.             else if (strcmp(argv[argnum], "-dump") == 0)
  598.                 gRunInfo.dumpOnErr = true;
  599.             else if (strcmp(argv[argnum], "-mem") == 0)
  600.                 gRunInfo.inMemory = true;
  601.             else if (strcmp(argv[argnum], "-threads") == 0)
  602.             {
  603.                 ++argnum;
  604.                 if (argnum >= argc)
  605.                     throw 1;
  606.                 gRunInfo.numThreads = atoi(argv[argnum]);
  607.                 if (gRunInfo.numThreads < 0)
  608.                     throw 1;
  609.             }
  610.             else if (strcmp(argv[argnum], "-time") == 0)
  611.             {
  612.                 ++argnum;
  613.                 if (argnum >= argc)
  614.                     throw 1;
  615.                 gRunInfo.totalTime = atoi(argv[argnum]);
  616.                 if (gRunInfo.totalTime < 1)
  617.                     throw 1;
  618.             }
  619.             else  if (argv[argnum][0] == '-')
  620.             {
  621.                 fprintf(stderr, "Unrecognized command line option.  Scanning "%s"n",
  622.                     argv[argnum]);
  623.                 throw 1;
  624.             }
  625.             else
  626.             {
  627.                 gRunInfo.numInputFiles++;
  628.                 if (gRunInfo.numInputFiles >= MAXINFILES)
  629.                 {
  630.                     fprintf(stderr, "Too many input files.  Limit is %dn", MAXINFILES);
  631.                     throw 1;
  632.                 }
  633.                 gRunInfo.files[gRunInfo.numInputFiles-1].fileName = argv[argnum];
  634.             }
  635.             argnum++;
  636.         }
  637.         // We've made it through the command line.
  638.         //  Verify that at least one input file to be parsed was specified.
  639.         if (gRunInfo.numInputFiles == 0)
  640.         {
  641.             fprintf(stderr, "No input XML file specified on command line.n");
  642.             throw 1;
  643.         };
  644.     }
  645.     catch (int)
  646.     {
  647.         fprintf(stderr, "usage:  threadtest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...n"
  648.             "     -v             Use validating parser.  Non-validating is default.n"
  649.             "     -n             Enable namespace processing. Defaults to off.n"
  650.             "     -s             Enable schema processing. Defaults to off.n"
  651.             "     -f             Enable full schema constraint checking. Defaults to off.n"
  652.             "     -parser=xxx    Parser Type [dom | sax].  Default is SAX.n"
  653.             "     -quiet         Suppress periodic status display.n"
  654.             "     -verbose       Display extra messages.n"
  655.             "     -reuse         Retain and reuse parser.  Default creates new for each parse.n"
  656.             "     -threads nnn   Number of threads.  Default is 2.n"
  657.             "     -time nnn      Total time to run, in seconds.  Default is forever.n"
  658.             "     -dump          Dump DOM tree on error.n"
  659.             "     -mem           Read files into memory once only, and parse them from there.nn"
  660.             );
  661.         exit(1);
  662.     }
  663. }
  664. //---------------------------------------------------------------------------
  665. //
  666. //   ReadFilesIntoMemory   For use when parsing from memory rather than
  667. //                          reading the files each time, here is the code that
  668. //                          reads the files into local memory buffers.
  669. //
  670. //                          This function is only called once, from the main
  671. //                          thread, before all of the worker threads are started.
  672. //
  673. //---------------------------------------------------------------------------
  674. void ReadFilesIntoMemory()
  675. {
  676.     int     fileNum;
  677.     FILE    *fileF;
  678.     size_t  t;
  679.     if (gRunInfo.inMemory)
  680.     {
  681.         for (fileNum = 0; fileNum <gRunInfo.numInputFiles; fileNum++)
  682.         {
  683.             InFileInfo *fInfo = &gRunInfo.files[fileNum];
  684.             fInfo->uFileName = XMLString::transcode(fInfo->fileName);
  685.             fileF = fopen( fInfo->fileName, "rb" );
  686.             if (fileF == 0) {
  687.                 fprintf(stderr, "Can not open file "%s".n", fInfo->fileName);
  688.                 clearFileInfoMemory();
  689.                 exit(-1);
  690.             }
  691.             fseek(fileF, 0, SEEK_END);
  692.             fInfo->fileSize = ftell(fileF);
  693.             fseek(fileF, 0, SEEK_SET);
  694.             fInfo->fileContent = new char[fInfo->fileSize + 1];
  695.             t = fread(fInfo->fileContent, 1, fInfo->fileSize, fileF);
  696.             if (t != fInfo->fileSize) {
  697.                 fprintf(stderr, "Error reading file "%s".n", fInfo->fileName);
  698.                 clearFileInfoMemory();
  699.                 exit(-1);
  700.             }
  701.             fclose(fileF);
  702.             fInfo->fileContent[fInfo->fileSize] = 0;
  703.         }
  704.     }
  705. }
  706. void clearFileInfoMemory()
  707. {
  708.     int     fileNum;
  709.     if (gRunInfo.inMemory)
  710.     {
  711.         for (fileNum = 0; fileNum <gRunInfo.numInputFiles; fileNum++)
  712.         {
  713.             InFileInfo *fInfo = &gRunInfo.files[fileNum];
  714.             XMLString::release(&fInfo->uFileName);
  715.             delete [] fInfo->fileContent;
  716.         }
  717.     }
  718. }
  719. //----------------------------------------------------------------------
  720. //
  721. //  threadMain   The main function for each of the swarm of test threads.
  722. //               Run in an infinite loop, parsing each of the documents
  723. //               given on the command line in turn.
  724. //
  725. //----------------------------------------------------------------------
  726. #ifdef PLATFORM_WIN32
  727. unsigned long WINAPI threadMain (void *param)
  728. #else
  729. extern "C" {
  730. void threadMain (void *param)
  731. #endif
  732. {
  733.     ThreadInfo   *thInfo = (ThreadInfo *)param;
  734.     ThreadParser *thParser = 0;
  735.     if (gRunInfo.verbose)
  736.         printf("Thread #%d: startingn", thInfo->fThreadNum);
  737.     int docNum = gRunInfo.numInputFiles;
  738.     //
  739.     // Each time through this loop, one file will be parsed and its checksum
  740.     // computed and compared with the precomputed value for that file.
  741.     //
  742.     while (gRunInfo.stopNow == false)
  743.     {
  744.         thInfo->fInProgress = true;
  745.         if (thParser == 0)
  746.             thParser = new ThreadParser;
  747.         docNum++;
  748.         if (docNum >= gRunInfo.numInputFiles)
  749.             docNum = 0;
  750.         InFileInfo *fInfo = &gRunInfo.files[docNum];
  751.         if (gRunInfo.verbose )
  752.             printf("Thread #%d: starting file %sn", thInfo->fThreadNum, fInfo->fileName);
  753.         int checkSum = 0;
  754.         checkSum = thParser->parse(docNum);
  755.         if (checkSum != gRunInfo.files[docNum].checkSum)
  756.         {
  757.             fprintf(stderr, "nThread %d: Parse Check sum error on file  "%s".  Expected %x,  got %xn",
  758.                 thInfo->fThreadNum, fInfo->fileName, fInfo->checkSum, checkSum);
  759.             // Revisit - let the loop continue to run?
  760.             int secondTryCheckSum = thParser->reCheck();
  761.             fprintf(stderr, "   Retry checksum is %xn", secondTryCheckSum);
  762.             if (gRunInfo.dumpOnErr) {
  763.                if (gRunInfo.dom)
  764.                   thParser->domPrint();
  765.             }
  766.             fflush(stdout);
  767.             clearFileInfoMemory();
  768.             exit(-1);
  769.         }
  770.         if (gRunInfo.reuseParser == false)
  771.         {
  772.             delete thParser;
  773.             thParser = 0;
  774.         }
  775.         thInfo->fHeartBeat = true;
  776.         thInfo->fParses++;
  777.         thInfo->fInProgress = false;
  778.     }
  779.     delete thParser;
  780. #ifdef PLATFORM_WIN32
  781.     return 0;
  782. #else
  783.     return;
  784. }
  785. #endif
  786. }
  787. //----------------------------------------------------------------------
  788. //
  789. //   main
  790. //
  791. //----------------------------------------------------------------------
  792. int main (int argc, char **argv)
  793. {
  794.     parseCommandLine(argc, argv);
  795.     //
  796.     // Initialize the XML system.
  797.     //
  798.     try
  799.     {
  800.          XMLPlatformUtils::Initialize();
  801.     }
  802.     catch (...)
  803.     {
  804.         fprintf(stderr, "Exception from XMLPlatfromUtils::Initialize.n");
  805.         return 1;
  806.     }
  807.     //
  808.     // If we will be parsing from memory, read each of the input files
  809.     //  into memory now.
  810.     //
  811.     ReadFilesIntoMemory();
  812.     //
  813.     // While we are still single threaded, parse each of the documents
  814.     //  once, to check for errors, and to note the checksum.
  815.     // Blow off the rest of the test if there are errors.
  816.     //
  817.     ThreadParser *mainParser = new ThreadParser;
  818.     int     n;
  819.     bool    errors = false;
  820.     int     cksum;
  821.     for (n = 0; n < gRunInfo.numInputFiles; n++)
  822.     {
  823.         char *fileName = gRunInfo.files[n].fileName;
  824.         if (gRunInfo.verbose)
  825.             printf("%s checksum is ", fileName);
  826.         cksum = mainParser->parse(n);
  827.         if (cksum == 0)
  828.         {
  829.             fprintf(stderr, "An error occurred while initially parsing %sn",
  830.                 fileName);
  831.             errors = true;
  832.         };
  833.         gRunInfo.files[n].checkSum = cksum;
  834.         if (gRunInfo.verbose )
  835.             printf("%xn", cksum);
  836.         if (gRunInfo.dumpOnErr && errors) {
  837.            if (gRunInfo.dom)
  838.               mainParser->domPrint();
  839.         }
  840.     }
  841.     delete mainParser;
  842.     //
  843.     //  Fire off the requested number of parallel threads
  844.     //
  845.     if (gRunInfo.numThreads == 0) {
  846.         clearFileInfoMemory();
  847.         exit(0);
  848.     }
  849.     gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
  850.     int threadNum;
  851.     for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  852.     {
  853.         gThreadInfo[threadNum].fThreadNum = threadNum;
  854.         ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
  855.     }
  856.     //
  857.     //  Loop, watching the heartbeat of the worker threads.
  858.     //    Each second, display "+" when all threads have completed a parse
  859.     //                 display "." if some thread hasn't since previous "+"
  860.     //
  861.     unsigned long startTime = XMLPlatformUtils::getCurrentMillis();
  862.     int elapsedSeconds = 0;
  863.     while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
  864.     {
  865.         ThreadFuncs::Sleep(1000);
  866.         if (gRunInfo.quiet == false && gRunInfo.verbose == false)
  867.         {
  868.             char c = '+';
  869.             int threadNum;
  870.             for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  871.             {
  872.                 if (gThreadInfo[threadNum].fHeartBeat == false)
  873.                 {
  874.                     c = '.';
  875.                     break;
  876.                 };
  877.             }
  878.             fputc(c, stdout);
  879.             fflush(stdout);
  880.             if (c == '+')
  881.                 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  882.                     gThreadInfo[threadNum].fHeartBeat = false;
  883.         }
  884.         elapsedSeconds = (XMLPlatformUtils::getCurrentMillis() - startTime) / 1000;
  885.     };
  886.     //
  887.     //  Time's up, we are done.  (We only get here if this was a timed run)
  888.     //  Tally up the total number of parses completed by each of the threads.
  889.     //
  890.     gRunInfo.stopNow = true;      // set flag, which will cause worker threads to stop.
  891.     //
  892.     //  Make sure all threads are done before terminate
  893.     //
  894.     for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) {
  895.         while (gThreadInfo[threadNum].fInProgress == true) {
  896.             ThreadFuncs::Sleep(1000);
  897.         }
  898.         if (gRunInfo.verbose)
  899.             printf("Thread #%d: is finished.n", threadNum);
  900.     }
  901.     //
  902.     //  We are done!   Count the number of parse and terminate the program
  903.     //
  904.     double totalParsesCompleted = 0;
  905.     for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  906.     {
  907.         totalParsesCompleted += gThreadInfo[threadNum].fParses;
  908.         // printf("%f   ", totalParsesCompleted);
  909.     }
  910.     if (gRunInfo.quiet == false) {
  911.         double parsesPerMinute = totalParsesCompleted / (double(gRunInfo.totalTime) / double(60));
  912.         printf("n%8.1f parses per minute.n", parsesPerMinute);
  913.     }
  914.     XMLPlatformUtils::Terminate();
  915.     clearFileInfoMemory();
  916.     delete [] gThreadInfo;
  917.     printf("Test Run Successfullyn");
  918.     return 0;
  919. }