/* * 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 #include #include #include #if defined(XALAN_CLASSIC_IOSTREAMS) #include #else #include #endif #include #include #include #include #if defined(WIN32) #include #include #define WIN32_LEAN_AND_MEAN #include #elif defined(XALAN_POSIX2_AVAILABLE) #include // This is a workaround for a Tru64 compiler bug... #if defined(XALAN_STRICT_ANSI_HEADERS) && defined(TRU64) #include typedef long sigjmp_buf[_JBLEN]; #endif #include #include #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 #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(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(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(&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 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; }