xref: /haiku/headers/tools/cppunit/ThreadManager.h (revision 1b89aa98ffe3057ab801dab67b9f5de6d1f933a5)
1530d2bc9STyler Dauwalder #ifndef _beos_thread_manager_h_
2530d2bc9STyler Dauwalder #define _beos_thread_manager_h_
3530d2bc9STyler Dauwalder 
4530d2bc9STyler Dauwalder #include <cppunit/Exception.h>
5530d2bc9STyler Dauwalder #include <cppunit/TestResult.h>
69285de51STyler Dauwalder #include <OS.h>
7530d2bc9STyler Dauwalder #include <signal.h>
8530d2bc9STyler Dauwalder #include <string>
9530d2bc9STyler Dauwalder 
10530d2bc9STyler Dauwalder // Pointer to a function that takes no parameters and
11530d2bc9STyler Dauwalder // returns no result. All threads must be implemented
12530d2bc9STyler Dauwalder // in a function of this type.
13530d2bc9STyler Dauwalder 
14530d2bc9STyler Dauwalder // Helper class to handle thread management
15530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
16*1b89aa98SIngo Weinhold class CPPUNIT_API BThreadManager {
17530d2bc9STyler Dauwalder public:
18530d2bc9STyler Dauwalder 	typedef void (TestClass::*ThreadMethod)();
19530d2bc9STyler Dauwalder 
200a99bdf4STyler Dauwalder 	BThreadManager(std::string threadName, TestClass *object, ThreadMethod method, sem_id &threadSem);
21530d2bc9STyler Dauwalder 	~BThreadManager();
22530d2bc9STyler Dauwalder 
23530d2bc9STyler Dauwalder     status_t LaunchThread(CppUnit::TestResult *result);
24530d2bc9STyler Dauwalder 
25530d2bc9STyler Dauwalder 	// Thread management methods
26530d2bc9STyler Dauwalder 	int32 Stop();
27530d2bc9STyler Dauwalder 	int32 WaitForThread();
28530d2bc9STyler Dauwalder 	bool IsRunning();
29530d2bc9STyler Dauwalder 
getName()30530d2bc9STyler Dauwalder 	std::string getName() const { return fName; }
31530d2bc9STyler Dauwalder 
32530d2bc9STyler Dauwalder protected:
33530d2bc9STyler Dauwalder 	std::string fName;
34530d2bc9STyler Dauwalder 	TestClass *fObject;
35530d2bc9STyler Dauwalder 	ThreadMethod fMethod;
36530d2bc9STyler Dauwalder 	thread_id fID;
37530d2bc9STyler Dauwalder 	CppUnit::TestResult *fTestResult;
380a99bdf4STyler Dauwalder 	sem_id &fThreadSem;
39530d2bc9STyler Dauwalder 
40530d2bc9STyler Dauwalder 	static long EntryFunction(BThreadManager<TestClass, ExpectedException>* manager);
41530d2bc9STyler Dauwalder 	void Run();
42530d2bc9STyler Dauwalder 
43530d2bc9STyler Dauwalder };
44530d2bc9STyler Dauwalder 
45530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
BThreadManager(std::string threadName,TestClass * object,ThreadMethod method,sem_id & threadSem)46530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::BThreadManager(
47530d2bc9STyler Dauwalder 	std::string threadName,
48530d2bc9STyler Dauwalder 	TestClass *object,
490a99bdf4STyler Dauwalder 	ThreadMethod method,
500a99bdf4STyler Dauwalder 	sem_id &threadSem
51530d2bc9STyler Dauwalder )
52530d2bc9STyler Dauwalder 	: fName(threadName)
53530d2bc9STyler Dauwalder 	, fObject(object)
54530d2bc9STyler Dauwalder 	, fMethod(method)
55530d2bc9STyler Dauwalder 	, fID(0)
56530d2bc9STyler Dauwalder 	, fTestResult(NULL)
570a99bdf4STyler Dauwalder 	, fThreadSem(threadSem)
58530d2bc9STyler Dauwalder {
59530d2bc9STyler Dauwalder }
60530d2bc9STyler Dauwalder 
61530d2bc9STyler Dauwalder 
62530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
~BThreadManager()63530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::~BThreadManager() {
64530d2bc9STyler Dauwalder 	Stop();
65530d2bc9STyler Dauwalder }
66530d2bc9STyler Dauwalder 
67530d2bc9STyler Dauwalder 
68530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
69530d2bc9STyler Dauwalder int32
WaitForThread()70530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::WaitForThread() {
71530d2bc9STyler Dauwalder 	int32 result = 0;
72530d2bc9STyler Dauwalder 	if (find_thread(NULL) != fID)
73530d2bc9STyler Dauwalder 		wait_for_thread(fID, &result);
74530d2bc9STyler Dauwalder 	return result;
75530d2bc9STyler Dauwalder }
76530d2bc9STyler Dauwalder 
77530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
78530d2bc9STyler Dauwalder int32
Stop()79530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::Stop() {
80530d2bc9STyler Dauwalder 	int32 result = 0;
81530d2bc9STyler Dauwalder 	if (find_thread(NULL) != fID) {
82530d2bc9STyler Dauwalder 		while (IsRunning()) {
83530d2bc9STyler Dauwalder 			kill(fID, SIGINT);
84530d2bc9STyler Dauwalder 			snooze(1000000);
85530d2bc9STyler Dauwalder 		}
86530d2bc9STyler Dauwalder 		result = WaitForThread();
87530d2bc9STyler Dauwalder 	}
88530d2bc9STyler Dauwalder 	return result;
89530d2bc9STyler Dauwalder }
90530d2bc9STyler Dauwalder 
91530d2bc9STyler Dauwalder 
92530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
93530d2bc9STyler Dauwalder bool
IsRunning(void)94530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::IsRunning(void) {
95530d2bc9STyler Dauwalder 	if (fID != 0) {
96530d2bc9STyler Dauwalder 		thread_info info;
97530d2bc9STyler Dauwalder 		if (get_thread_info(fID, &info) == B_OK)
98530d2bc9STyler Dauwalder 			return true;
99530d2bc9STyler Dauwalder 		else
100530d2bc9STyler Dauwalder 			fID = 0;
101530d2bc9STyler Dauwalder 	}
102530d2bc9STyler Dauwalder 	return false;
103530d2bc9STyler Dauwalder }
104530d2bc9STyler Dauwalder 
105530d2bc9STyler Dauwalder 
106530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
107530d2bc9STyler Dauwalder status_t
LaunchThread(CppUnit::TestResult * result)108530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::LaunchThread(CppUnit::TestResult *result) {
109530d2bc9STyler Dauwalder 	if (IsRunning())
110530d2bc9STyler Dauwalder 		return B_ALREADY_RUNNING;
111530d2bc9STyler Dauwalder 
112530d2bc9STyler Dauwalder 	fTestResult = result;
113530d2bc9STyler Dauwalder 	fID = spawn_thread((thread_entry)(BThreadManager::EntryFunction),
114530d2bc9STyler Dauwalder 		fName.c_str(), B_NORMAL_PRIORITY, this);
115530d2bc9STyler Dauwalder 
116530d2bc9STyler Dauwalder 	status_t err;
117530d2bc9STyler Dauwalder 	if (fID == B_NO_MORE_THREADS || fID == B_NO_MEMORY) {
118530d2bc9STyler Dauwalder 		err = fID;
119530d2bc9STyler Dauwalder 		fID = 0;
120530d2bc9STyler Dauwalder 	} else {
1210a99bdf4STyler Dauwalder 		// Aquire the semaphore, then start the thread.
1220a99bdf4STyler Dauwalder 		if (acquire_sem(fThreadSem) != B_OK)
1230a99bdf4STyler Dauwalder 			throw CppUnit::Exception("BThreadManager::LaunchThread() -- Error acquiring thread semaphore");
124530d2bc9STyler Dauwalder 		err = resume_thread(fID);
125530d2bc9STyler Dauwalder 	}
126530d2bc9STyler Dauwalder 	return err;
127530d2bc9STyler Dauwalder }
128530d2bc9STyler Dauwalder 
129530d2bc9STyler Dauwalder 
130530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
131530d2bc9STyler Dauwalder long
EntryFunction(BThreadManager<TestClass,ExpectedException> * manager)132530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::EntryFunction(BThreadManager<TestClass, ExpectedException> *manager) {
133530d2bc9STyler Dauwalder 	manager->Run();
134530d2bc9STyler Dauwalder 	return 0;
135530d2bc9STyler Dauwalder }
136530d2bc9STyler Dauwalder 
137530d2bc9STyler Dauwalder template <class TestClass, class ExpectedException>
138530d2bc9STyler Dauwalder void
Run(void)139530d2bc9STyler Dauwalder BThreadManager<TestClass, ExpectedException>::Run(void) {
140530d2bc9STyler Dauwalder 	// These outer try/catch blocks handle unexpected exceptions.
141530d2bc9STyler Dauwalder 	// Said exceptions are caught and noted in the TestResult
142530d2bc9STyler Dauwalder 	// class, but not allowed to escape and disrupt the other
143530d2bc9STyler Dauwalder 	// threads that are assumingly running concurrently.
144530d2bc9STyler Dauwalder 	try {
145530d2bc9STyler Dauwalder 
146530d2bc9STyler Dauwalder 		// Our parent ThreadedTestCaller should check fObject to be non-NULL,
147530d2bc9STyler Dauwalder 		// but we'll do it here too just to be sure.
148530d2bc9STyler Dauwalder 		if (!fObject)
149530d2bc9STyler Dauwalder 			throw CppUnit::Exception("BThreadManager::Run() -- NULL fObject pointer");
150530d2bc9STyler Dauwalder 
151530d2bc9STyler Dauwalder 		// Before running, we need to add this thread's name to
152530d2bc9STyler Dauwalder 		// the object's id->(name,subtestnum) map.
153530d2bc9STyler Dauwalder 		fObject->InitThreadInfo(fID, fName);
154530d2bc9STyler Dauwalder 
155530d2bc9STyler Dauwalder 		// This inner try/catch block is for expected exceptions.
156530d2bc9STyler Dauwalder 		// If we get through it without an exception, we have to
157530d2bc9STyler Dauwalder 		// raise a different exception that makes note of the fact
158530d2bc9STyler Dauwalder 		// that the exception we were expecting didn't arrive. If
159530d2bc9STyler Dauwalder 		// no exception is expected, then nothing is done (see
160530d2bc9STyler Dauwalder 		// "cppunit/TestCaller.h" for detail on the classes used
161530d2bc9STyler Dauwalder 		// to handle this behaviour).
162530d2bc9STyler Dauwalder 		try {
163530d2bc9STyler Dauwalder 			(fObject->*fMethod)();
164530d2bc9STyler Dauwalder 	    } catch ( ExpectedException & ) {
165530d2bc9STyler Dauwalder 			return;
166530d2bc9STyler Dauwalder 		}
167530d2bc9STyler Dauwalder 	  	CppUnit::ExpectedExceptionTraits<ExpectedException>::expectedException();
168530d2bc9STyler Dauwalder 
169530d2bc9STyler Dauwalder 	} catch ( CppUnit::Exception &e ) {
170530d2bc9STyler Dauwalder 		// Add on the thread name, then note the exception
171530d2bc9STyler Dauwalder         CppUnit::Exception *threadException = new CppUnit::Exception(
172530d2bc9STyler Dauwalder         	std::string(e.what()) + " (thread: " + fName + ")",
173530d2bc9STyler Dauwalder         	e.sourceLine()
174530d2bc9STyler Dauwalder         );
175530d2bc9STyler Dauwalder 		fTestResult->addFailure( fObject, threadException );
176530d2bc9STyler Dauwalder 	}
177530d2bc9STyler Dauwalder 	catch ( std::exception &e ) {
178530d2bc9STyler Dauwalder 		// Add on the thread name, then note the exception
179530d2bc9STyler Dauwalder         CppUnit::Exception *threadException = new CppUnit::Exception(
180530d2bc9STyler Dauwalder         	std::string(e.what()) + " (thread: " + fName + ")"
181530d2bc9STyler Dauwalder         );
182530d2bc9STyler Dauwalder 		fTestResult->addError( fObject, threadException );
183530d2bc9STyler Dauwalder 	}
184530d2bc9STyler Dauwalder 	catch (...) {
185530d2bc9STyler Dauwalder 		// Add on the thread name, then note the exception
186530d2bc9STyler Dauwalder 		CppUnit::Exception *threadException = new CppUnit::Exception(
187530d2bc9STyler Dauwalder 			"caught unknown exception (thread: " + fName + ")"
188530d2bc9STyler Dauwalder 		);
189530d2bc9STyler Dauwalder 		fTestResult->addError( fObject, threadException );
190530d2bc9STyler Dauwalder 	}
191530d2bc9STyler Dauwalder 
1920a99bdf4STyler Dauwalder 	// Release the semaphore we acquired earlier
1930a99bdf4STyler Dauwalder 	release_sem(fThreadSem);
194530d2bc9STyler Dauwalder }
195530d2bc9STyler Dauwalder 
196530d2bc9STyler Dauwalder 
197530d2bc9STyler Dauwalder #endif
198