headers/bsd: Add sys/queue.h.
[haiku.git] / headers / tools / cppunit / ThreadManager.h
blob712dee6ca075ae4adb97d2c78b7ecef4a67ddc4f
1 #ifndef _beos_thread_manager_h_
2 #define _beos_thread_manager_h_
4 #include <cppunit/Exception.h>
5 #include <cppunit/TestResult.h>
6 #include <OS.h>
7 #include <signal.h>
8 #include <string>
10 // Pointer to a function that takes no parameters and
11 // returns no result. All threads must be implemented
12 // in a function of this type.
14 // Helper class to handle thread management
15 template <class TestClass, class ExpectedException>
16 class CPPUNIT_API BThreadManager {
17 public:
18 typedef void (TestClass::*ThreadMethod)();
20 BThreadManager(std::string threadName, TestClass *object, ThreadMethod method, sem_id &threadSem);
21 ~BThreadManager();
23 status_t LaunchThread(CppUnit::TestResult *result);
25 // Thread management methods
26 int32 Stop();
27 int32 WaitForThread();
28 bool IsRunning();
30 std::string getName() const { return fName; }
32 protected:
33 std::string fName;
34 TestClass *fObject;
35 ThreadMethod fMethod;
36 thread_id fID;
37 CppUnit::TestResult *fTestResult;
38 sem_id &fThreadSem;
40 static long EntryFunction(BThreadManager<TestClass, ExpectedException>* manager);
41 void Run();
45 template <class TestClass, class ExpectedException>
46 BThreadManager<TestClass, ExpectedException>::BThreadManager(
47 std::string threadName,
48 TestClass *object,
49 ThreadMethod method,
50 sem_id &threadSem
52 : fName(threadName)
53 , fObject(object)
54 , fMethod(method)
55 , fID(0)
56 , fTestResult(NULL)
57 , fThreadSem(threadSem)
62 template <class TestClass, class ExpectedException>
63 BThreadManager<TestClass, ExpectedException>::~BThreadManager() {
64 Stop();
68 template <class TestClass, class ExpectedException>
69 int32
70 BThreadManager<TestClass, ExpectedException>::WaitForThread() {
71 int32 result = 0;
72 if (find_thread(NULL) != fID)
73 wait_for_thread(fID, &result);
74 return result;
77 template <class TestClass, class ExpectedException>
78 int32
79 BThreadManager<TestClass, ExpectedException>::Stop() {
80 int32 result = 0;
81 if (find_thread(NULL) != fID) {
82 while (IsRunning()) {
83 kill(fID, SIGINT);
84 snooze(1000000);
86 result = WaitForThread();
88 return result;
92 template <class TestClass, class ExpectedException>
93 bool
94 BThreadManager<TestClass, ExpectedException>::IsRunning(void) {
95 if (fID != 0) {
96 thread_info info;
97 if (get_thread_info(fID, &info) == B_OK)
98 return true;
99 else
100 fID = 0;
102 return false;
106 template <class TestClass, class ExpectedException>
107 status_t
108 BThreadManager<TestClass, ExpectedException>::LaunchThread(CppUnit::TestResult *result) {
109 if (IsRunning())
110 return B_ALREADY_RUNNING;
112 fTestResult = result;
113 fID = spawn_thread((thread_entry)(BThreadManager::EntryFunction),
114 fName.c_str(), B_NORMAL_PRIORITY, this);
116 status_t err;
117 if (fID == B_NO_MORE_THREADS || fID == B_NO_MEMORY) {
118 err = fID;
119 fID = 0;
120 } else {
121 // Aquire the semaphore, then start the thread.
122 if (acquire_sem(fThreadSem) != B_OK)
123 throw CppUnit::Exception("BThreadManager::LaunchThread() -- Error acquiring thread semaphore");
124 err = resume_thread(fID);
126 return err;
130 template <class TestClass, class ExpectedException>
131 long
132 BThreadManager<TestClass, ExpectedException>::EntryFunction(BThreadManager<TestClass, ExpectedException> *manager) {
133 manager->Run();
134 return 0;
137 template <class TestClass, class ExpectedException>
138 void
139 BThreadManager<TestClass, ExpectedException>::Run(void) {
140 // These outer try/catch blocks handle unexpected exceptions.
141 // Said exceptions are caught and noted in the TestResult
142 // class, but not allowed to escape and disrupt the other
143 // threads that are assumingly running concurrently.
144 try {
146 // Our parent ThreadedTestCaller should check fObject to be non-NULL,
147 // but we'll do it here too just to be sure.
148 if (!fObject)
149 throw CppUnit::Exception("BThreadManager::Run() -- NULL fObject pointer");
151 // Before running, we need to add this thread's name to
152 // the object's id->(name,subtestnum) map.
153 fObject->InitThreadInfo(fID, fName);
155 // This inner try/catch block is for expected exceptions.
156 // If we get through it without an exception, we have to
157 // raise a different exception that makes note of the fact
158 // that the exception we were expecting didn't arrive. If
159 // no exception is expected, then nothing is done (see
160 // "cppunit/TestCaller.h" for detail on the classes used
161 // to handle this behaviour).
162 try {
163 (fObject->*fMethod)();
164 } catch ( ExpectedException & ) {
165 return;
167 CppUnit::ExpectedExceptionTraits<ExpectedException>::expectedException();
169 } catch ( CppUnit::Exception &e ) {
170 // Add on the thread name, then note the exception
171 CppUnit::Exception *threadException = new CppUnit::Exception(
172 std::string(e.what()) + " (thread: " + fName + ")",
173 e.sourceLine()
175 fTestResult->addFailure( fObject, threadException );
177 catch ( std::exception &e ) {
178 // Add on the thread name, then note the exception
179 CppUnit::Exception *threadException = new CppUnit::Exception(
180 std::string(e.what()) + " (thread: " + fName + ")"
182 fTestResult->addError( fObject, threadException );
184 catch (...) {
185 // Add on the thread name, then note the exception
186 CppUnit::Exception *threadException = new CppUnit::Exception(
187 "caught unknown exception (thread: " + fName + ")"
189 fTestResult->addError( fObject, threadException );
192 // Release the semaphore we acquired earlier
193 release_sem(fThreadSem);
197 #endif