ThreadTest.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:30k
源码类别:

xml/soap/webservice

开发平台:

C/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.13 2001/11/23 16:16:10 tng Exp $
  58.  *
  59.  * @author Andy Heninger, IBM
  60.  */
  61. #include <stdlib.h>
  62. #include <stdio.h>
  63. #include <string.h>
  64. #include <parsers/SAXParser.hpp>
  65. #include <parsers/DOMParser.hpp>
  66. #include <util/PlatformUtils.hpp>
  67. #include <sax/HandlerBase.hpp>
  68. #include <framework/MemBufInputSource.hpp>
  69. #include <dom/DOM.hpp>
  70. //------------------------------------------------------------------------------
  71. //
  72. //   Windows specific code for starting threads
  73. //
  74. //------------------------------------------------------------------------------
  75. #ifdef PLATFORM_WIN32
  76. #include "Windows.h"
  77. #include "process.h"
  78. typedef void (*ThreadFunc)(void *);
  79. class ThreadFuncs           // This class isolates OS dependent threading
  80. {                           //   functions from the rest of ThreadTest program.
  81. public:
  82.     static void Sleep(int millis) {::Sleep(millis);};
  83.     static void startThread(ThreadFunc, void *param);
  84. };
  85. void ThreadFuncs::startThread(ThreadFunc func, void *param)
  86. {
  87.     unsigned long x;
  88.     x = _beginthread(func, 0x10000, param);
  89.     if (x == -1)
  90.     {
  91.         fprintf(stderr, "Error starting thread.  Errno = %dn", errno);
  92.         exit(-1);
  93.     }
  94. }
  95. #elif defined (AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) || defined (OS390)
  96. #include <pthread.h>
  97. #include <unistd.h>
  98. #include <errno.h>
  99. //------------------------------------------------------------------------------
  100. //
  101. //   UNIX specific code for starting threads
  102. //
  103. //------------------------------------------------------------------------------
  104. extern "C" {
  105. typedef void (*ThreadFunc)(void *);
  106. typedef void *(*pthreadfunc)(void *);
  107. class ThreadFuncs           // This class isolates OS dependent threading
  108. {                           //   functions from the rest of ThreadTest program.
  109. public:
  110.     static void Sleep(int millis);
  111.     static void startThread(ThreadFunc, void *param);
  112. };
  113. void ThreadFuncs::Sleep(int millis)
  114. {
  115.    int seconds = millis/1000;
  116.    if (seconds <= 0) seconds = 1;
  117.    ::sleep(seconds);
  118. }
  119. void ThreadFuncs::startThread(ThreadFunc func, void *param)
  120. {
  121.     unsigned long x;
  122.     pthread_t tId;
  123.     //thread_t tId;
  124. #if defined(_HP_UX) && defined(XML_USE_DCE)
  125.     x = pthread_create( &tId, pthread_attr_default,  (pthreadfunc)func,  param);
  126. #else
  127.     pthread_attr_t attr;
  128.     pthread_attr_init(&attr);
  129.     x = pthread_create( &tId, &attr,  (pthreadfunc)func,  param);
  130. #endif
  131.     if (x == -1)
  132.     {
  133.         fprintf(stderr, "Error starting thread.  Errno = %dn", errno);
  134.         exit(-1);
  135.     }
  136. }
  137. }
  138. #else
  139. #error This platform is not supported
  140. #endif
  141. //------------------------------------------------------------------------------
  142. //
  143. //  struct InFileInfo   One of these structs will be set up for each file listed
  144. //                      on the command line.  Once set, the data is unchanging
  145. //                      and can safely be referenced by the test threads without
  146. //                      use of synchronization.
  147. //
  148. //------------------------------------------------------------------------------
  149. struct InFileInfo
  150. {
  151.     char    *fileName;
  152.     char    *fileContent;    // If doing an in-memory parse, this field points
  153.                              //   to an allocated string containing the entire file
  154.                              //   contents.  Otherwise it's 0.
  155.     size_t  fileSize;        // The file length.  Only initialized when doing
  156.                              //   an in-memory test.
  157.     int     checkSum;        // The XML checksum.  Set up by the main thread for
  158.                              //   each file before the worker threads are started.
  159. };
  160. //------------------------------------------------------------------------------
  161. //
  162. //  struct runInfo     Holds the info extracted from the command line.
  163. //                     There is only one of these, and it is static, and
  164. //                     unchanging once the command line has been parsed.
  165. //                     During the test, the threads will access this info without
  166. //                     any synchronization.
  167. //
  168. //------------------------------------------------------------------------------
  169. const int MAXINFILES = 25;
  170. struct RunInfo
  171. {
  172.     bool        quiet;
  173.     bool        verbose;
  174.     int         numThreads;
  175.     bool        validating;
  176.     bool        dom;
  177.     bool        reuseParser;
  178.     bool        inMemory;
  179.     bool        dumpOnErr;
  180.     int         totalTime;
  181.     int         numInputFiles;
  182.     InFileInfo  files[MAXINFILES];
  183. };
  184. //------------------------------------------------------------------------------
  185. //
  186. //  struct threadInfo  Holds information specific to an individual thread.
  187. //                     One of these is set up for each thread in the test.
  188. //                     The main program monitors the threads by looking
  189. //                     at the status stored in these structs.
  190. //
  191. //------------------------------------------------------------------------------
  192. struct ThreadInfo
  193. {
  194.     bool    fHeartBeat;            // Set true by the thread each time it finishes
  195.                                    //   parsing a file.
  196.     unsigned int     fParses;      // Number of parses completed.
  197.     int              fThreadNum;   // Identifying number for this thread.
  198.     ThreadInfo() {
  199.         fHeartBeat = false;
  200.         fParses = 0;
  201.         fThreadNum = -1;
  202.     }
  203. };
  204. //
  205. //------------------------------------------------------------------------------
  206. //
  207. //  Global Data
  208. //
  209. //------------------------------------------------------------------------------
  210. RunInfo         gRunInfo;
  211. ThreadInfo      *gThreadInfo;
  212. //------------------------------------------------------------------------------
  213. //
  214. //  class ThreadParser   Bundles together a SAX parser and the SAX handlers
  215. //                       and contains the API that the rest of this test
  216. //                       program uses for creating parsers and doing parsing.
  217. //
  218. //                       Multiple instances of this class can operate concurrently
  219. //                       in different threads.
  220. //
  221. //-------------------------------------------------------------------------------
  222. class ThreadParser: public HandlerBase
  223. {
  224. private:
  225.     int           fCheckSum;
  226.     SAXParser*    fSAXParser;
  227.     DOMParser*    fDOMParser;
  228. public:                               //  This is the API used by the rest of the test program
  229.     ThreadParser();
  230.     ~ThreadParser();
  231.     int parse(int fileNum);           // Parse the specified file.  fileNum is an index
  232.                                       //   into the gRunInfo.files array.
  233.                                       //  return the XML checksum, or
  234.                                       //  0 if a parse error occured.
  235.     int reCheck();                    // Try to compute the checksum again.
  236.                                       //  for DOM, re-walk the tree.
  237.                                       //  for SAX, can't do, just return previous value.
  238.     void domPrint(const DOM_Node &node); // Dump out the contents of a node,
  239.     void domPrint();                   //   including any children.  Default (no param)
  240.                                        //   version dumps the entire document.
  241. private:
  242.     ThreadParser(const ThreadParser &); // No copy constructor
  243.     const ThreadParser & operator =(const ThreadParser &); // No assignment.
  244.     void  addToCheckSum(const XMLCh *chars, int len=-1);
  245.     void  domCheckSum(const DOM_Node &);
  246. public:                               // Not really public,
  247.                                       //  These are the SAX call-back functions
  248.                                       //  that this class implements.
  249.     void startElement(const XMLCh* const name, AttributeList& attributes);
  250.     void characters(const XMLCh* const chars, const unsigned int length) {
  251.         addToCheckSum(chars, length);};
  252.     void ignorableWhitespace(const XMLCh* const chars, const unsigned int length) {
  253.         addToCheckSum(chars, length);};
  254.     void resetDocument() {};
  255.     void warning(const SAXParseException& exception)     {
  256.         fprintf(stderr, "*** Warning ");
  257.         throw;};
  258.     void error(const SAXParseException& exception)       {
  259.         fprintf(stderr, "*** Error ");
  260.         throw;};
  261.     void fatalError(const SAXParseException& exception)  {
  262.         fprintf(stderr, "***** Fatal error ");
  263.         throw;};
  264. };
  265. //
  266. //  ThreadParser constructor.  Invoked by the threads of the test program
  267. //                              to create parsers.
  268. //
  269. ThreadParser::ThreadParser()
  270. {
  271.     fSAXParser = 0;
  272.     fDOMParser = 0;
  273.     if (gRunInfo.dom) {
  274.         // Set up to use a DOM parser
  275.         fDOMParser = new DOMParser;
  276.         fDOMParser->setDoValidation(gRunInfo.validating);
  277.         fDOMParser->setErrorHandler(this);
  278.     }
  279.     else
  280.     {
  281.         // Set up to use a SAX parser.
  282.         fSAXParser = new SAXParser;
  283.         fSAXParser->setDoValidation(gRunInfo.validating);
  284.         fSAXParser->setDocumentHandler(this);
  285.         fSAXParser->setErrorHandler(this);
  286.     }
  287. }
  288. ThreadParser::~ThreadParser()
  289. {
  290.      delete fSAXParser;
  291.      delete fDOMParser;
  292. }
  293. //------------------------------------------------------------------------
  294. //
  295. //  parse   - This is the method that is invoked by the rest of
  296. //            the test program to actually parse an XML file.
  297. //
  298. //------------------------------------------------------------------------
  299. int ThreadParser::parse(int fileNum)
  300. {
  301.     MemBufInputSource *mbis = 0;
  302.     InFileInfo        *fInfo = &gRunInfo.files[fileNum];
  303.     fCheckSum = 0;
  304.     if (gRunInfo.inMemory) {
  305.         mbis = new  MemBufInputSource((const XMLByte *) fInfo->fileContent,
  306.                                        fInfo->fileSize,
  307.                                        fInfo->fileName,
  308.                                        false);
  309.     }
  310.     try
  311.     {
  312.         if (gRunInfo.dom) {
  313.             // Do a DOM parse
  314.             if (gRunInfo.inMemory)
  315.                 fDOMParser->parse(*mbis);
  316.             else
  317.                 fDOMParser->parse(fInfo->fileName);
  318.             DOM_Document doc = fDOMParser->getDocument();
  319.             domCheckSum(doc);
  320.         }
  321.         else
  322.         {
  323.             // Do a SAX parse
  324.             if (gRunInfo.inMemory)
  325.                 fSAXParser->parse(*mbis);
  326.             else
  327.                 fSAXParser->parse(fInfo->fileName);
  328.         }
  329.     }
  330.     catch (const XMLException& e)
  331.     {
  332.         char *exceptionMessage = XMLString::transcode(e.getMessage());
  333.         fprintf(stderr, " during parsing: %s n Exception message is: %s n",
  334.             fInfo->fileName, exceptionMessage);
  335.         delete exceptionMessage;
  336.     }
  337.     delete mbis;
  338.     return fCheckSum;
  339. }
  340. //
  341. //  addToCheckSum - private function, used within ThreadParser in
  342. //                  computing the checksum of the XML file.
  343. //
  344. //                  Unichar Strings to be added to the checksum
  345. //                  can either be null terminated (omit len param, which
  346. //                  will then default to -1), or provide an explicit
  347. //                  length.
  348. //
  349. void ThreadParser::addToCheckSum(const XMLCh *chars, int len)
  350. {
  351.     if (len == -1)
  352.     {
  353.         // Null terminated string.
  354.         while (*chars != 0)
  355.         {
  356.             fCheckSum = fCheckSum*5 + *chars;
  357.             chars++;
  358.         }
  359.     }
  360.     else
  361.     {
  362.         // String with character count.
  363.         int i;
  364.         for (i=0; i<len; i++)
  365.             fCheckSum = fCheckSum*5 + chars[i];
  366.     }
  367. }
  368. //
  369. // startElement - our SAX handler callback function for element starts.
  370. //                update the document checksum with the element name
  371. //                and any attribute names and values.
  372. //
  373. void ThreadParser::startElement(const XMLCh *const name, AttributeList &attributes)
  374. {
  375.     addToCheckSum(name);
  376.     int n = attributes.getLength();
  377.     int i;
  378.     for (i=0; i<n; i++)
  379.     {
  380.         const XMLCh *attNam = attributes.getName(i);
  381.         addToCheckSum(attNam);
  382.         const XMLCh *attVal = attributes.getValue(i);
  383.         addToCheckSum(attVal);
  384.     }
  385. }
  386. //
  387. // domCheckSum  -  Compute the check sum for a DOM node.
  388. //                 Works recursively - initially called with a document node.
  389. //
  390. void ThreadParser::domCheckSum(const DOM_Node &node)
  391. {
  392.     DOMString         s;
  393.     DOM_Node          child;
  394.     DOM_NamedNodeMap  attributes;
  395.     switch (node.getNodeType() )
  396.     {
  397.     case DOM_Node::ELEMENT_NODE:
  398.         {
  399.             s = node.getNodeName();   // the element name
  400.             attributes = node.getAttributes();  // Element's attributes
  401.             int numAttributes = attributes.getLength();
  402.             int i;
  403.             for (i=0; i<numAttributes; i++)
  404.                 domCheckSum(attributes.item(i));
  405.             addToCheckSum(s.rawBuffer(), s.length());  // Content and Children
  406.             for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
  407.                 domCheckSum(child);
  408.             break;
  409.         }
  410.     case DOM_Node::ATTRIBUTE_NODE:
  411.         {
  412.             s = node.getNodeName();  // The attribute name
  413.             addToCheckSum(s.rawBuffer(), s.length());
  414.             s = node.getNodeValue();  // The attribute value
  415.             if (s != 0)
  416.                 addToCheckSum(s.rawBuffer(), s.length());
  417.             break;
  418.         }
  419.     case DOM_Node::TEXT_NODE:
  420.     case DOM_Node::CDATA_SECTION_NODE:
  421.         {
  422.             s = node.getNodeValue();
  423.             addToCheckSum(s.rawBuffer(), s.length());
  424.             break;
  425.         }
  426.     case DOM_Node::ENTITY_REFERENCE_NODE:
  427.     case DOM_Node::DOCUMENT_NODE:
  428.         {
  429.             // For entity references and the document, nothing is dirctly
  430.             //  added to the checksum, but we do want to process the chidren nodes.
  431.             //
  432.             for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
  433.                 domCheckSum(child);
  434.             break;
  435.         }
  436.     }
  437. }
  438. //
  439. // Recompute the checksum.  Meaningful only for DOM, will tell us whether
  440. //  a failure is transient, or whether the DOM data is permanently corrupted.
  441. //
  442. int ThreadParser::reCheck()
  443. {
  444.     if (gRunInfo.dom) {
  445.         fCheckSum = 0;
  446.         DOM_Document doc = fDOMParser->getDocument();
  447.         domCheckSum(doc);
  448.     }
  449.     return fCheckSum;
  450. }
  451. //
  452. // domPrint  -  Dump the contents of a DOM node.
  453. //              For debugging failures, when all else fails.
  454. //                 Works recursively - initially called with a document node.
  455. //
  456. void ThreadParser::domPrint()
  457. {
  458.     DOMString("Begin DOMPrint ...n").print();
  459.     if (gRunInfo.dom)
  460.         domPrint(fDOMParser->getDocument());
  461.     DOMString("End DOMPrintn").print();
  462. }
  463. void ThreadParser::domPrint(const DOM_Node &node)
  464. {
  465.     DOMString         s;
  466.     DOM_Node          child;
  467.     DOM_NamedNodeMap  attributes;
  468.     switch (node.getNodeType() )
  469.     {
  470.     case DOM_Node::ELEMENT_NODE:
  471.         {
  472.             DOMString("<").print();
  473.             node.getNodeName().print();   // the element name
  474.             attributes = node.getAttributes();  // Element's attributes
  475.             int numAttributes = attributes.getLength();
  476.             int i;
  477.             for (i=0; i<numAttributes; i++) {
  478.                 domPrint(attributes.item(i));
  479.             }
  480.             DOMString(">").print();
  481.             for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
  482.                 domPrint(child);
  483.             DOMString("</").print();
  484.             node.getNodeName().print();
  485.             DOMString(">").print();
  486.             break;
  487.         }
  488.     case DOM_Node::ATTRIBUTE_NODE:
  489.         {
  490.             DOMString(" ").print();
  491.             node.getNodeName().print();   // The attribute name
  492.             DOMString("= "").print();
  493.             node.getNodeValue().print();  // The attribute value
  494.             DOMString(""").print();
  495.             break;
  496.         }
  497.     case DOM_Node::TEXT_NODE:
  498.     case DOM_Node::CDATA_SECTION_NODE:
  499.         {
  500.             node.getNodeValue().print();
  501.             break;
  502.         }
  503.     case DOM_Node::ENTITY_REFERENCE_NODE:
  504.     case DOM_Node::DOCUMENT_NODE:
  505.         {
  506.             // For entity references and the document, nothing is dirctly
  507.             //  printed, but we do want to process the chidren nodes.
  508.             //
  509.             for (child=node.getFirstChild(); child!=0; child=child.getNextSibling())
  510.                 domPrint(child);
  511.             break;
  512.         }
  513.     }
  514. }
  515. //----------------------------------------------------------------------
  516. //
  517. //   parseCommandLine   Read through the command line, and save all
  518. //                      of the options in the gRunInfo struct.
  519. //
  520. //                      Display the usage message if the command line
  521. //                      is no good.
  522. //
  523. //                      Probably ought to be a member function of RunInfo.
  524. //
  525. //----------------------------------------------------------------------
  526. void parseCommandLine(int argc, char **argv)
  527. {
  528.     gRunInfo.quiet = false;               // Set up defaults for run.
  529.     gRunInfo.verbose = false;
  530.     gRunInfo.numThreads = 2;
  531.     gRunInfo.validating = false;
  532.     gRunInfo.dom = false;
  533.     gRunInfo.reuseParser = false;
  534.     gRunInfo.inMemory = false;
  535.     gRunInfo.dumpOnErr = false;
  536.     gRunInfo.totalTime = 0;
  537.     gRunInfo.numInputFiles = 0;
  538.     try             // Use exceptions for command line syntax errors.
  539.     {
  540.         int argnum = 1;
  541.         while (argnum < argc)
  542.         {
  543.             if (strcmp(argv[argnum], "-quiet") == 0)
  544.                 gRunInfo.quiet = true;
  545.             else if (strcmp(argv[argnum], "-verbose") == 0)
  546.                 gRunInfo.verbose = true;
  547.             else if (strcmp(argv[argnum], "-v") == 0)
  548.                 gRunInfo.validating = true;
  549.             else if (strcmp(argv[argnum], "-dom") == 0)
  550.                 gRunInfo.dom = true;
  551.             else if (strcmp(argv[argnum], "-reuse") == 0)
  552.                 gRunInfo.reuseParser = true;
  553.             else if (strcmp(argv[argnum], "-dump") == 0)
  554.                 gRunInfo.dumpOnErr = true;
  555.             else if (strcmp(argv[argnum], "-mem") == 0)
  556.                 gRunInfo.inMemory = true;
  557.             else if (strcmp(argv[argnum], "-threads") == 0)
  558.             {
  559.                 ++argnum;
  560.                 if (argnum >= argc)
  561.                     throw 1;
  562.                 gRunInfo.numThreads = atoi(argv[argnum]);
  563.                 if (gRunInfo.numThreads < 0)
  564.                     throw 1;
  565.             }
  566.             else if (strcmp(argv[argnum], "-time") == 0)
  567.             {
  568.                 ++argnum;
  569.                 if (argnum >= argc)
  570.                     throw 1;
  571.                 gRunInfo.totalTime = atoi(argv[argnum]);
  572.                 if (gRunInfo.totalTime < 1)
  573.                     throw 1;
  574.             }
  575.             else  if (argv[argnum][0] == '-')
  576.             {
  577.                 fprintf(stderr, "Unrecognized command line option.  Scanning "%s"n",
  578.                     argv[argnum]);
  579.                 throw 1;
  580.             }
  581.             else
  582.             {
  583.                 gRunInfo.numInputFiles++;
  584.                 if (gRunInfo.numInputFiles >= MAXINFILES)
  585.                 {
  586.                     fprintf(stderr, "Too many input files.  Limit is %dn", MAXINFILES);
  587.                     throw 1;
  588.                 }
  589.                 gRunInfo.files[gRunInfo.numInputFiles-1].fileName = argv[argnum];
  590.             }
  591.             argnum++;
  592.         }
  593.         // We've made it through the command line.
  594.         //  Verify that at least one input file to be parsed was specified.
  595.         if (gRunInfo.numInputFiles == 0)
  596.         {
  597.             fprintf(stderr, "No input XML file specified on command line.n");
  598.             throw 1;
  599.         };
  600.     }
  601.     catch (int)
  602.     {
  603.         fprintf(stderr, "usage:  threadtest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...n"
  604.             "     -v             Use validating parser.  Non-validating is default. n"
  605.             "     -dom           Use a DOM parser.  Default is SAX. n"
  606.             "     -quiet         Suppress periodic status display. n"
  607.             "     -verbose       Display extra messages. n"
  608.             "     -reuse         Retain and reuse parser.  Default creates new for each parse.n"
  609.             "     -threads nnn   Number of threads.  Default is 2. n"
  610.             "     -time nnn      Total time to run, in seconds.  Default is forever.n"
  611.             "     -dump          Dump DOM tree on error.n"
  612.             "     -mem           Read files into memory once only, and parse them from there.n"
  613.             );
  614.         exit(1);
  615.     }
  616. }
  617. //---------------------------------------------------------------------------
  618. //
  619. //   ReadFilesIntoMemory   For use when parsing from memory rather than
  620. //                          reading the files each time, here is the code that
  621. //                          reads the files into local memory buffers.
  622. //
  623. //                          This function is only called once, from the main
  624. //                          thread, before all of the worker threads are started.
  625. //
  626. //---------------------------------------------------------------------------
  627. void ReadFilesIntoMemory()
  628. {
  629.     int     fileNum;
  630.     FILE    *fileF;
  631.     size_t  t;
  632.     if (gRunInfo.inMemory)
  633.     {
  634.         for (fileNum = 0; fileNum <gRunInfo.numInputFiles; fileNum++)
  635.         {
  636.             InFileInfo *fInfo = &gRunInfo.files[fileNum];
  637.             fileF = fopen( fInfo->fileName, "rb" );
  638.             if (fileF == 0) {
  639.                 fprintf(stderr, "Can not open file "%s".n", fInfo->fileName);
  640.                 exit(-1);
  641.             }
  642.             fseek(fileF, 0, SEEK_END);
  643.             fInfo->fileSize = ftell(fileF);
  644.             fseek(fileF, 0, SEEK_SET);
  645.             fInfo->fileContent = new char[fInfo->fileSize + 1];
  646.             t = fread(fInfo->fileContent, 1, fInfo->fileSize, fileF);
  647.             if (t != fInfo->fileSize) {
  648.                 fprintf(stderr, "Error reading file "%s".n", fInfo->fileName);
  649.                 exit(-1);
  650.             }
  651.             fclose(fileF);
  652.             fInfo->fileContent[fInfo->fileSize] = 0;
  653.         }
  654.     }
  655. }
  656. //----------------------------------------------------------------------
  657. //
  658. //  threadMain   The main function for each of the swarm of test threads.
  659. //               Run in an infinite loop, parsing each of the documents
  660. //               given on the command line in turn.
  661. //
  662. //               There is no return from this fuction, and no graceful
  663. //               thread termination.  Threads are stuck running here
  664. //               until the OS shuts them down as a consequence of the
  665. //               main thread of the process (which never calls this
  666. //               function) exiting.
  667. //
  668. //----------------------------------------------------------------------
  669. extern "C" {
  670. void threadMain (void *param)
  671. {
  672.     ThreadInfo   *thInfo = (ThreadInfo *)param;
  673.     ThreadParser *thParser = 0;
  674.     if (gRunInfo.verbose)
  675.         printf("Thread #%d: startingn", thInfo->fThreadNum);
  676.     int docNum = gRunInfo.numInputFiles;
  677.     //
  678.     // Each time through this loop, one file will be parsed and its checksum
  679.     // computed and compared with the precomputed value for that file.
  680.     //
  681.     while (true)
  682.     {
  683.         if (thParser == 0)
  684.             thParser = new ThreadParser;
  685.         docNum++;
  686.         if (docNum >= gRunInfo.numInputFiles)
  687.             docNum = 0;
  688.         InFileInfo *fInfo = &gRunInfo.files[docNum];
  689.         if (gRunInfo.verbose )
  690.             printf("Thread #%d: starting file %sn", thInfo->fThreadNum, fInfo->fileName);
  691.         int checkSum = 0;
  692.         checkSum = thParser->parse(docNum);
  693.         if (checkSum != gRunInfo.files[docNum].checkSum)
  694.         {
  695.             fprintf(stderr, "nThread %d: Parse Check sum error on file  "%s".  Expected %x,  got %xn",
  696.                 thInfo->fThreadNum, fInfo->fileName, fInfo->checkSum, checkSum);
  697.             // Revisit - let the loop continue to run?
  698.             int secondTryCheckSum = thParser->reCheck();
  699.             fprintf(stderr, "   Retry checksum is %xn", secondTryCheckSum);
  700.             if (gRunInfo.dumpOnErr)
  701.                 thParser->domPrint();
  702.             fflush(stdout);
  703.             exit(-1);
  704.         }
  705.         if (gRunInfo.reuseParser == false)
  706.         {
  707.             delete thParser;
  708.             thParser = 0;
  709.         }
  710.         thInfo->fHeartBeat = true;
  711.         thInfo->fParses++;
  712.     }
  713. }
  714. }
  715. //----------------------------------------------------------------------
  716. //
  717. //   main
  718. //
  719. //----------------------------------------------------------------------
  720. int main (int argc, char **argv)
  721. {
  722.     parseCommandLine(argc, argv);
  723.     //
  724.     // Initialize the XML system.
  725.     //
  726.     try
  727.     {
  728.          XMLPlatformUtils::Initialize();
  729.     }
  730.     catch (...)
  731.     {
  732.         fprintf(stderr, "Exception from XMLPlatfromUtils::Initialize.n");
  733.         return 1;
  734.     }
  735.     //
  736.     // If we will be parsing from memory, read each of the input files
  737.     //  into memory now.
  738.     //
  739.     ReadFilesIntoMemory();
  740.     //
  741.     // While we are still single threaded, parse each of the documents
  742.     //  once, to check for errors, and to note the checksum.
  743.     // Blow off the rest of the test if there are errors.
  744.     //
  745.     ThreadParser *mainParser = new ThreadParser;
  746.     int     n;
  747.     bool    errors = false;
  748.     int     cksum;
  749.     for (n = 0; n < gRunInfo.numInputFiles; n++)
  750.     {
  751.         char *fileName = gRunInfo.files[n].fileName;
  752.         if (gRunInfo.verbose)
  753.             printf("%s checksum is ", fileName);
  754.         cksum = mainParser->parse(n);
  755.         if (cksum == 0)
  756.         {
  757.             fprintf(stderr, "An error occured while initially parsing %sn",
  758.                 fileName);
  759.             errors = true;
  760.         };
  761.         gRunInfo.files[n].checkSum = cksum;
  762.         if (gRunInfo.verbose )
  763.             printf("%xn", cksum);
  764.         if (gRunInfo.dumpOnErr && errors)
  765.             mainParser->domPrint();
  766.     }
  767.     if (errors)
  768.         exit(1);
  769.     //
  770.     //  Fire off the requested number of parallel threads
  771.     //
  772.     if (gRunInfo.numThreads == 0)
  773.         exit(0);
  774.     gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
  775.     int threadNum;
  776.     for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  777.     {
  778.         gThreadInfo[threadNum].fThreadNum = threadNum;
  779.         ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
  780.     }
  781.     //
  782.     //  Loop, watching the heartbeat of the worker threads.
  783.     //    Each second, display "+" when all threads have completed a parse
  784.     //                 display "." if some thread hasn't since previous "+"
  785.     //
  786.     unsigned long startTime = XMLPlatformUtils::getCurrentMillis();
  787.     int elapsedSeconds = 0;
  788.     while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
  789.     {
  790.         ThreadFuncs::Sleep(1000);
  791.         if (gRunInfo.quiet == false && gRunInfo.verbose == false)
  792.         {
  793.             char c = '+';
  794.             int threadNum;
  795.             for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  796.             {
  797.                 if (gThreadInfo[threadNum].fHeartBeat == false)
  798.                 {
  799.                     c = '.';
  800.                     break;
  801.                 };
  802.             }
  803.             fputc(c, stdout);
  804.             fflush(stdout);
  805.             if (c == '+')
  806.                 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  807.                     gThreadInfo[threadNum].fHeartBeat = false;
  808.         }
  809.         elapsedSeconds = (XMLPlatformUtils::getCurrentMillis() - startTime) / 1000;
  810.     };
  811.     //
  812.     //  Time's up, we are done.  (We only get here if this was a timed run)
  813.     //  Tally up the total number of parses completed by each of the threads.
  814.     //  To Do:  Run the main thread at higher priority, so that the worker threads
  815.     //    won't make much progress while we are adding up the results.
  816.     //
  817.     double totalParsesCompleted = 0;
  818.     for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
  819.     {
  820.         totalParsesCompleted += gThreadInfo[threadNum].fParses;
  821.         // printf("%f   ", totalParsesCompleted);
  822.     }
  823.     double parsesPerMinute = totalParsesCompleted / (double(gRunInfo.totalTime) / double(60));
  824.     printf("n%8.1f parses per minute.", parsesPerMinute);
  825.     //  The threads are still running; we just return
  826.     //   and leave it to the operating sytem to kill them.
  827.     //
  828.     return 0;
  829. }