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