#ifndef _beos_thread_manager_h_ #define _beos_thread_manager_h_ #include #include #include #include #include // Pointer to a function that takes no parameters and // returns no result. All threads must be implemented // in a function of this type. // Helper class to handle thread management template class BThreadManager { public: typedef void (TestClass::*ThreadMethod)(); BThreadManager(std::string threadName, TestClass *object, ThreadMethod method, sem_id &threadSem); ~BThreadManager(); status_t LaunchThread(CppUnit::TestResult *result); // Thread management methods int32 Stop(); int32 WaitForThread(); bool IsRunning(); std::string getName() const { return fName; } protected: std::string fName; TestClass *fObject; ThreadMethod fMethod; thread_id fID; CppUnit::TestResult *fTestResult; sem_id &fThreadSem; static long EntryFunction(BThreadManager* manager); void Run(); }; template BThreadManager::BThreadManager( std::string threadName, TestClass *object, ThreadMethod method, sem_id &threadSem ) : fName(threadName) , fObject(object) , fMethod(method) , fID(0) , fTestResult(NULL) , fThreadSem(threadSem) { } template BThreadManager::~BThreadManager() { Stop(); } template int32 BThreadManager::WaitForThread() { int32 result = 0; if (find_thread(NULL) != fID) wait_for_thread(fID, &result); return result; } template int32 BThreadManager::Stop() { int32 result = 0; if (find_thread(NULL) != fID) { while (IsRunning()) { kill(fID, SIGINT); snooze(1000000); } result = WaitForThread(); } return result; } template bool BThreadManager::IsRunning(void) { if (fID != 0) { thread_info info; if (get_thread_info(fID, &info) == B_OK) return true; else fID = 0; } return false; } template status_t BThreadManager::LaunchThread(CppUnit::TestResult *result) { if (IsRunning()) return B_ALREADY_RUNNING; fTestResult = result; fID = spawn_thread((thread_entry)(BThreadManager::EntryFunction), fName.c_str(), B_NORMAL_PRIORITY, this); status_t err; if (fID == B_NO_MORE_THREADS || fID == B_NO_MEMORY) { err = fID; fID = 0; } else { // Aquire the semaphore, then start the thread. if (acquire_sem(fThreadSem) != B_OK) throw CppUnit::Exception("BThreadManager::LaunchThread() -- Error acquiring thread semaphore"); err = resume_thread(fID); } return err; } template long BThreadManager::EntryFunction(BThreadManager *manager) { manager->Run(); return 0; } template void BThreadManager::Run(void) { // These outer try/catch blocks handle unexpected exceptions. // Said exceptions are caught and noted in the TestResult // class, but not allowed to escape and disrupt the other // threads that are assumingly running concurrently. try { // Our parent ThreadedTestCaller should check fObject to be non-NULL, // but we'll do it here too just to be sure. if (!fObject) throw CppUnit::Exception("BThreadManager::Run() -- NULL fObject pointer"); // Before running, we need to add this thread's name to // the object's id->(name,subtestnum) map. fObject->InitThreadInfo(fID, fName); // This inner try/catch block is for expected exceptions. // If we get through it without an exception, we have to // raise a different exception that makes note of the fact // that the exception we were expecting didn't arrive. If // no exception is expected, then nothing is done (see // "cppunit/TestCaller.h" for detail on the classes used // to handle this behaviour). try { (fObject->*fMethod)(); } catch ( ExpectedException & ) { return; } CppUnit::ExpectedExceptionTraits::expectedException(); } catch ( CppUnit::Exception &e ) { // Add on the thread name, then note the exception CppUnit::Exception *threadException = new CppUnit::Exception( std::string(e.what()) + " (thread: " + fName + ")", e.sourceLine() ); fTestResult->addFailure( fObject, threadException ); } catch ( std::exception &e ) { // Add on the thread name, then note the exception CppUnit::Exception *threadException = new CppUnit::Exception( std::string(e.what()) + " (thread: " + fName + ")" ); fTestResult->addError( fObject, threadException ); } catch (...) { // Add on the thread name, then note the exception CppUnit::Exception *threadException = new CppUnit::Exception( "caught unknown exception (thread: " + fName + ")" ); fTestResult->addError( fObject, threadException ); } // Release the semaphore we acquired earlier release_sem(fThreadSem); } #endif