Logo Search packages:      
Sourcecode: xalan version File versions  Download package

ThreadTest.cpp

/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Base header file.  Must be first.
#include <xalanc/Include/PlatformDefinitions.hpp>

#include <xalanc/Include/XalanMemoryManagement.hpp>

#include <cassert>
#include <ctime>



#if defined(XALAN_CLASSIC_IOSTREAMS)
#include <iostream.h>
#else
#include <iostream>
#endif



#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/Mutexes.hpp>



#include <xalanc/Include/XalanAutoPtr.hpp>



#include <xalanc/XalanTransformer/XalanTransformer.hpp>



#if defined(WIN32)

#include <csignal>
#include <process.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#elif defined(XALAN_POSIX2_AVAILABLE)

#include <csignal>

// This is a workaround for a Tru64 compiler bug...
#if defined(XALAN_STRICT_ANSI_HEADERS) && defined(TRU64)
#include <csetjmp>
typedef long sigjmp_buf[_JBLEN];
#endif
#include <pthread.h>
#include <unistd.h>

#else
#error Unsupported platform!
#endif



XALAN_USING_STD(cerr)
XALAN_USING_STD(cout)
XALAN_USING_STD(endl)


      
#if defined(XALAN_STRICT_ANSI_HEADERS)
      using std::atoi;
      using std::signal;
      using std::strcmp;
#endif

      
      
      // This is here for memory leak testing.
#if defined(_DEBUG)
#include <crtdbg.h>
#endif



typedef XERCES_CPP_NAMESPACE_QUALIFIER XMLMutex             XMLMutexType;
typedef XERCES_CPP_NAMESPACE_QUALIFIER XMLMutexLock         XMLMutexLockType;



class SynchronizedCounter
{
public:

      SynchronizedCounter();

      ~SynchronizedCounter();

      void
      increment();

      void
      decrement();

      long
      getCounter() const;

private:

      XMLMutexType      m_mutex;

      long              m_counter;
};



SynchronizedCounter::SynchronizedCounter() :
      m_mutex(),
      m_counter(0)
{
}



SynchronizedCounter::~SynchronizedCounter()
{
}



void
SynchronizedCounter::increment()
{
      const XMLMutexLockType  theLock(&m_mutex);

      if (m_counter < LONG_MAX)
      {
            ++m_counter;
      }
}



void
SynchronizedCounter::decrement()
{
      const XMLMutexLockType  theLock(&m_mutex);

      if (m_counter > 0)
      {
            --m_counter;
      }
}



long
SynchronizedCounter::getCounter() const
{
      return m_counter;
}



struct
ThreadInfo
{
      ThreadInfo(
                  long                          theThreadNumber = 0L,
                  SynchronizedCounter*    theCounter = 0) :
            m_threadNumber(theThreadNumber),
            m_counter(theCounter),
            m_done(false)
      {
      }

      long                          m_threadNumber;

      SynchronizedCounter*    m_counter;

      bool                          m_done;
};



XALAN_USING_XALAN(XalanCompiledStylesheet)
XALAN_USING_XALAN(XalanDOMChar)
XALAN_USING_XALAN(XalanDOMString)
XALAN_USING_XALAN(XalanParsedSource)



// Used to hold compiled stylesheet and pre-parsed source...
const XalanCompiledStylesheet*      glbCompiledStylesheet = 0;
const XalanParsedSource*            glbParsedSource = 0;
bool                                      fContinue = true;

const XalanDOMChar*                       theStylesheetFileName = 0;
const XalanDOMChar*                       theSourceFileName = 0;


#if defined(WIN32)
static BOOL __stdcall
signalHandler(DWORD           theSignalType)
{
      if (theSignalType == CTRL_C_EVENT ||
            theSignalType == CTRL_BREAK_EVENT)
      {
            fContinue = false;

            return TRUE;
      }
      else
      {
            return FALSE;
      }
}
#elif defined(XALAN_POSIX2_AVAILABLE)
extern "C"
{
static void
signalHandler(int)
{
      fContinue = false;
}
}
#else
#error Unsupported platform!
#endif



#if defined(WIN32)

extern "C"
{
      void thePreparsedThreadRoutine(void* param);

      typedef void (*ThreadRoutineType)(void* param);
}

void
#elif defined(XALAN_POSIX2_AVAILABLE)

extern "C"
{
      void* thePreparsedThreadRoutine(void* param);

      typedef void* (*ThreadRoutineType)(void* param);
}

void*
#else
#error Unsupported platform!
#endif
thePreparsedThreadRoutine(void*           param)
{
// This routine uses compiled stylesheet (glbStylesheetRoot), which is set using the 
// theProcessor.setStylesheetRoot method. The transform is done using the theProcessor's
// process() method.

#if defined(XALAN_OLD_STYLE_CASTS)
      ThreadInfo* const       theInfo = (ThreadInfo*)param;
#else
      ThreadInfo* const       theInfo = reinterpret_cast<ThreadInfo*>(param);
#endif

      assert(theInfo != 0);

      theInfo->m_counter->increment();

    XALAN_USING_XALAN(MemoryManagerType)
    XALAN_USING_XALAN(XalanMemMgrs)

    MemoryManagerType& theManager = XalanMemMgrs::getDefaultXercesMemMgr();

      try
      {
            XALAN_USING_XALAN(LongToDOMString)
            XALAN_USING_XALAN(XalanTransformer)

            // Our input file.  The assumption is that the executable will be run
            // from same directory as the input files.

            // Generate the output file name.
            XalanDOMString    theOutputFile(XALAN_STATIC_UCODE_STRING("birds"), theManager);

            LongToDOMString(theInfo->m_threadNumber, theOutputFile);
        theOutputFile.append(".out");

            // Create a transformer...
            XalanTransformer  theTransformer(theManager);

        XALAN_USING_XALAN(XSLTResultTarget)

            // Do the transform...
            theTransformer.transform(*glbParsedSource, glbCompiledStylesheet, XSLTResultTarget( theOutputFile, theManager));
      }
      catch(...)
      {
            cerr << "Exception caught in thread " << theInfo->m_threadNumber;
      }

      // Decrement the counter because we're done...
      theInfo->m_counter->decrement();

      theInfo->m_done = true;

#if defined(XALAN_POSIX2_AVAILABLE)
      return 0;
#endif
}



#if defined(WIN32)

extern "C" void theUnparsedThreadRoutine(void* param);

void
#elif defined(XALAN_POSIX2_AVAILABLE)

extern "C" void* theUnparsedThreadRoutine(void* param);

void*
#else
#error Unsupported platform!
#endif
theUnparsedThreadRoutine(void*            param)
{
// This routine compiles a stylesheet and a source document

#if defined(XALAN_OLD_STYLE_CASTS)
      ThreadInfo* const       theInfo = (ThreadInfo*)param;
#else
      ThreadInfo* const       theInfo = reinterpret_cast<ThreadInfo*>(param);
#endif

      assert(theInfo != 0);

      theInfo->m_counter->increment();

      try
      {
            XALAN_USING_XALAN(LongToDOMString)
            XALAN_USING_XALAN(XalanTransformer)

            // Our input file.  The assumption is that the executable will be run
            // from same directory as the input files.

        XALAN_USING_XALAN(MemoryManagerType)
        XALAN_USING_XALAN(XalanMemMgrs)

        MemoryManagerType& theManager = XalanMemMgrs::getDefaultXercesMemMgr();

        // Generate the output file name.
        XalanDOMString  theOutputFile(XALAN_STATIC_UCODE_STRING("birds"), theManager);

            LongToDOMString(theInfo->m_threadNumber, theOutputFile);
        theOutputFile.append(".out");

            // Create a transformer...
            XalanTransformer  theTransformer( theManager );

            assert(theSourceFileName != 0 && theStylesheetFileName != 0);

        XALAN_USING_XALAN(XSLTResultTarget)

            // Do the transform...
            theTransformer.transform(
                  theSourceFileName,
                  theStylesheetFileName,
                  XSLTResultTarget( theOutputFile, theManager));
      }
      catch(...)
      {
            cerr << "Exception caught in thread " << theInfo->m_threadNumber;
      }

      // Decrement the counter because we're done...
      theInfo->m_counter->decrement();

      theInfo->m_done = true;

#if defined(XALAN_POSIX2_AVAILABLE)
      return 0;
#endif
}



inline void
doSleep(unsigned int    theMilliseconds)
{
#if defined(WIN32)
      Sleep(theMilliseconds);
#elif defined(XALAN_POSIX2_AVAILABLE)
      usleep(theMilliseconds * 10);
#else
#error Unsupported platform!
#endif
}



bool
createThread(
                  ThreadInfo&             theThreadInfo,
                  ThreadRoutineType theThreadRoutine)
{
      theThreadInfo.m_done = false;

#if defined(WIN32)

      const unsigned long           theThreadID =
                  _beginthread(theThreadRoutine, 4096, reinterpret_cast<LPVOID>(&theThreadInfo));

      if (theThreadID == unsigned(-1))
      {
            theThreadInfo.m_done = true;

            return false;
      }
      else
      {
            return true;
      }

#elif defined(XALAN_POSIX2_AVAILABLE)

      pthread_t   theThread;

      const int   theResult = pthread_create(&theThread, 0, theThreadRoutine, (void*)&theThreadInfo);

      if (theResult != 0)
      {
            theThreadInfo.m_done = true;

            return false;
      }
      else
      {
#if defined(OS390)
            pthread_detach(&theThread);
#else
            pthread_detach(theThread);
#endif

            return true;
      }
#else
#error Unsupported platform!
#endif
}



void
doCountedThreads(
                  const SynchronizedCounter&    theCounter,
                  clock_t&                            theClock)
{
      cout << "Waiting for active threads to finish..." << endl;

      unsigned int      theCheckCount = 0;

      do
      {
            doSleep(2000);

            // Check a couple of times, just in case, since
            // getCounter() is not synchronized...
            if (theCounter.getCounter() == 0)
            {
                  if (theCheckCount == 0)
                  {
                        theClock = clock();
                  }

                  ++theCheckCount;
            }
      }
      while(theCheckCount < 2);
}



void
startThread(
                  ThreadInfo                          theThreadInfo[],
                  long                                theThreadNumber)
{
      bool  fResult = false;

      const bool  fPreparsed = theThreadNumber % 2 == 0 ? true : false;

      if (fPreparsed == true)
      {
            fResult = createThread(theThreadInfo[theThreadNumber], thePreparsedThreadRoutine);
      }
      else
      {
            fResult = createThread(theThreadInfo[theThreadNumber], theUnparsedThreadRoutine);
      }

      if (fResult == false)
      {
            cerr << endl << "Unable to create thread!" << endl;
      }
      else
      {
            cout << "Started thread number " << theThreadNumber << ", using ";

            if (fPreparsed == true)
            {
                  cout << "pre-parsed documents." << endl;
            }
            else
            {
                  cout << "unparsed documents." << endl;
            }
      }
}



void
doContinuousThreads(
                  const SynchronizedCounter&    theCounter,
                  ThreadInfo                          theThreadInfo[],
                  long                                theThreadCount,
                  clock_t&                            theClock)
{
      while(fContinue == true)
      {
            if (theCounter.getCounter() < theThreadCount)
            {
                  for (long i = 0; i < theThreadCount && fContinue == true; ++i)
                  {
                        if (theThreadInfo[i].m_done == true)
                        {
                              startThread(theThreadInfo, i);
                        }
                  }
            }
      }

      doCountedThreads(theCounter, theClock);
}



void
doThreads(
                  long  theThreadCount,
                  bool  fContinuous)
{
      if (fContinuous == true)
      {
#if defined(WIN32)
            SetConsoleCtrlHandler(
                        signalHandler,
                        TRUE);
#elif defined(XALAN_POSIX2_AVAILABLE)
            signal(SIGINT, signalHandler);
#else
#error Unsupported platform!
#endif

            cout << endl << "Running in continuous mode." << endl;
      }

      cout << endl << "Starting " << theThreadCount << " threads." << endl;

      XALAN_USING_XALAN(XalanArrayAutoPtr)

      XalanArrayAutoPtr<ThreadInfo> theThreadInfo(new ThreadInfo[theThreadCount]);

      try
      {
            cout << endl << "Clock before starting threads: " << clock() << endl;

            SynchronizedCounter           theCounter;

            long  i = 0;

            while (i < theThreadCount && fContinue == true)
            {
                  theThreadInfo[i].m_threadNumber = i;
                  theThreadInfo[i].m_counter = &theCounter;

                  startThread(theThreadInfo.get(), i);

                  ++i;
            }

            clock_t           theClock = 0;

            if (i == 0)
            {
                  cerr << endl << "No threads were created!" << endl;
            }
            else
            {
                  if (fContinuous == true)
                  {
                        doContinuousThreads(
                              theCounter,
                              theThreadInfo.get(),
                              theThreadCount,
                              theClock);
                  }
                  else
                  {
                        doCountedThreads(theCounter, theClock);
                  }
            }

            cout << endl << "Clock after threads: " << theClock << endl;
      }
      catch(...)
      {
            cerr << "Exception caught!!!"
                   << endl
                  << endl;
      }
}



void
Usage()
{
      cerr << "Usage: ThreadTest [-c] [count]"
             << endl
             << endl;
}



int
main(
                  int         argc,
                  char* argv[])
{
#if !defined(NDEBUG) && defined(_MSC_VER)
      _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

      _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
      _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
#endif

      if (argc > 3)
      {
            Usage();
      }
      else
      {
            bool  fContinuous = false;
            int         threadCount = 0;

            if (argc == 1)
            {
                  threadCount = 60;
            }
            else
            {
                  if (strcmp(argv[1], "-c") == 0)
                  {
                        fContinuous = true;
                  }

                  if (argc == 2)
                  {
                        if (fContinuous == true)
                        {
                              threadCount = 60;
                        }
                        else
                        {
                              threadCount = atoi(argv[1]);
                        }
                  }
                  else if (argc == 3)
                  {
                        if (fContinuous == true)
                        {
                              threadCount = atoi(argv[2]);
                        }
                        else
                        {
                              Usage();
                        }
                  }
            }

            if (threadCount > 0)
            {
                  try
                  {
                        XALAN_USING_XERCES(XMLPlatformUtils)

                        XALAN_USING_XALAN(XalanTransformer)

                        // Initialize Xerces...
                        XMLPlatformUtils::Initialize();

                        // Initialize Xalan...
                        XalanTransformer::initialize();

                        try
                        {
                              // Create a XalanTransformer.  We won't actually use this to transform --
                              // it's just acting as a factory for the compiled stylesheet and
                              // pre-parsed source document.  Note that we can't let the individual
                              // threads use this as a factory without serializing access to it, but
                              // we can share the stylesheet and source document.
                    XALAN_USING_XALAN(MemoryManagerType)
                    XALAN_USING_XALAN(XalanMemMgrs)

                    MemoryManagerType& theManager = XalanMemMgrs::getDefaultXercesMemMgr();

                    XalanTransformer            theXalanTransformer(theManager);

                    const XalanDOMString  theXSLFileName("birds.xsl", theManager);

                              theStylesheetFileName = theXSLFileName.c_str();

                              theXalanTransformer.compileStylesheet(theStylesheetFileName, glbCompiledStylesheet);
                              assert(glbCompiledStylesheet != 0);

                              // Compile the XML source document as well. All threads will use
                              // this binary representation of the source tree.
                              const XalanDOMString    theXMLFileName("birds.xml", theManager);

                              theSourceFileName = theXMLFileName.c_str();

                              theXalanTransformer.parseSource(theSourceFileName, glbParsedSource);
                              assert(glbParsedSource != 0);

                              doThreads(threadCount, fContinuous);

                              theStylesheetFileName = 0;
                              theSourceFileName = 0;
                        }
                        catch(...)
                        {
                              cerr << "Exception caught!!!"
                                     << endl
                                     << endl;
                        }

                        // Terminate Xalan...
                        XalanTransformer::terminate();

                        // Terminate Xerces...
                        XMLPlatformUtils::Terminate();

                        // Clean up the ICU, if it's integrated.
                        XalanTransformer::ICUCleanUp();
                  }
                  catch(...)
                  {
                        cerr << "Initialization failed!!!"
                               << endl
                               << endl;
                  }
            }
      } 

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index