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

xml/soap/webservice

开发平台:

C/C++

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