xref: /haiku/src/tests/kits/app/RegistrarThreadManagerTest.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
183f04694STyler Dauwalder #include "RegistrarThreadManagerTest.h"
283f04694STyler Dauwalder 
383f04694STyler Dauwalder #include <cppunit/Test.h>
483f04694STyler Dauwalder #include <cppunit/TestCaller.h>
583f04694STyler Dauwalder #include <cppunit/TestSuite.h>
683f04694STyler Dauwalder #include <TestApp.h>
783f04694STyler Dauwalder #include <TestUtils.h>
883f04694STyler Dauwalder 
977b9927bSIngo Weinhold #ifndef TEST_R5
10bef39d09SClemens Zeidler #include "RegistrarThread.h"
11bef39d09SClemens Zeidler #include "RegistrarThreadManager.h"
1283f04694STyler Dauwalder #endif	// !TEST_R5
1383f04694STyler Dauwalder 
1483f04694STyler Dauwalder #include <stdio.h>
1583f04694STyler Dauwalder 
1683f04694STyler Dauwalder // Suite
1783f04694STyler Dauwalder CppUnit::Test*
Suite()1883f04694STyler Dauwalder RegistrarThreadManagerTest::Suite() {
1983f04694STyler Dauwalder 	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
2083f04694STyler Dauwalder 	typedef CppUnit::TestCaller<RegistrarThreadManagerTest> TC;
2183f04694STyler Dauwalder 
22cc24797bSTyler Dauwalder 	suite->addTest( new TC("RegistrarThreadManager::Shutdown Test",
2383f04694STyler Dauwalder 						   &RegistrarThreadManagerTest::ShutdownTest) );
24cc24797bSTyler Dauwalder 	suite->addTest( new TC("RegistrarThreadManager::Thread Limit Test",
25cc24797bSTyler Dauwalder 						   &RegistrarThreadManagerTest::ThreadLimitTest) );
2683f04694STyler Dauwalder 
2783f04694STyler Dauwalder 
2883f04694STyler Dauwalder 	return suite;
2983f04694STyler Dauwalder }
3083f04694STyler Dauwalder 
3177b9927bSIngo Weinhold #ifndef TEST_R5
3283f04694STyler Dauwalder // Base test thread class
3383f04694STyler Dauwalder class TestThread : public RegistrarThread {
3483f04694STyler Dauwalder public:
TestThread(const char * name,int32 priority,BMessenger managerMessenger)3583f04694STyler Dauwalder 	TestThread(const char *name, int32 priority, BMessenger managerMessenger)
3683f04694STyler Dauwalder 		: RegistrarThread(name, priority, managerMessenger)
3783f04694STyler Dauwalder 	{
3883f04694STyler Dauwalder 	}
3983f04694STyler Dauwalder 
DoSomethingUseless()4083f04694STyler Dauwalder 	void DoSomethingUseless() {
4183f04694STyler Dauwalder 		fIntVal++;
4283f04694STyler Dauwalder 		snooze(1000);
4383f04694STyler Dauwalder 	}
4483f04694STyler Dauwalder 
4583f04694STyler Dauwalder private:
4683f04694STyler Dauwalder 	int64 fIntVal;
4783f04694STyler Dauwalder };
4883f04694STyler Dauwalder 
4983f04694STyler Dauwalder // Test thread that terminates quickly
5083f04694STyler Dauwalder class TerminatingThread : public TestThread {
5183f04694STyler Dauwalder public:
TerminatingThread(const char * name,int32 priority,BMessenger managerMessenger)5283f04694STyler Dauwalder 	TerminatingThread(const char *name, int32 priority, BMessenger managerMessenger)
5383f04694STyler Dauwalder 		: TestThread(name, priority, managerMessenger)
5483f04694STyler Dauwalder 	{
5583f04694STyler Dauwalder 	}
5683f04694STyler Dauwalder 
5783f04694STyler Dauwalder protected:
ThreadFunction()5883f04694STyler Dauwalder 	virtual status_t ThreadFunction() {
5983f04694STyler Dauwalder 		DoSomethingUseless();
6083f04694STyler Dauwalder 		fIsFinished = true;
6183f04694STyler Dauwalder 		return B_OK;
6283f04694STyler Dauwalder 	}
6383f04694STyler Dauwalder };
6483f04694STyler Dauwalder 
6583f04694STyler Dauwalder // Test thread that never terminates, but pays attention
6683f04694STyler Dauwalder // to its fShouldExit member
6783f04694STyler Dauwalder class WellBehavedInfiniteThread : public TestThread {
6883f04694STyler Dauwalder public:
WellBehavedInfiniteThread(const char * name,int32 priority,BMessenger managerMessenger)6983f04694STyler Dauwalder 	WellBehavedInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger)
7083f04694STyler Dauwalder 		: TestThread(name, priority, managerMessenger)
7183f04694STyler Dauwalder 	{
7283f04694STyler Dauwalder 	}
7383f04694STyler Dauwalder 
7483f04694STyler Dauwalder protected:
ThreadFunction()7583f04694STyler Dauwalder 	virtual status_t ThreadFunction() {
7683f04694STyler Dauwalder 		while (true) {
7783f04694STyler Dauwalder 			DoSomethingUseless();
7883f04694STyler Dauwalder 			if (fShouldExit)
7983f04694STyler Dauwalder 				break;
8083f04694STyler Dauwalder 		}
8183f04694STyler Dauwalder 		fIsFinished = true;
8283f04694STyler Dauwalder 		return B_OK;
8383f04694STyler Dauwalder 	}
8483f04694STyler Dauwalder };
8583f04694STyler Dauwalder 
8683f04694STyler Dauwalder // Test thread that never terminates and completely ignores
8783f04694STyler Dauwalder // its fShouldExit member
8883f04694STyler Dauwalder class NaughtyInfiniteThread : public TestThread {
8983f04694STyler Dauwalder public:
NaughtyInfiniteThread(const char * name,int32 priority,BMessenger managerMessenger)9083f04694STyler Dauwalder 	NaughtyInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger)
9183f04694STyler Dauwalder 		: TestThread(name, priority, managerMessenger)
9283f04694STyler Dauwalder 	{
9383f04694STyler Dauwalder 	}
9483f04694STyler Dauwalder 
9583f04694STyler Dauwalder protected:
ThreadFunction()9683f04694STyler Dauwalder 	virtual status_t ThreadFunction() {
9783f04694STyler Dauwalder 		while (true) {
9883f04694STyler Dauwalder 			DoSomethingUseless();
9983f04694STyler Dauwalder 		}
10083f04694STyler Dauwalder 		fIsFinished = true;
10183f04694STyler Dauwalder 		return B_OK;
10283f04694STyler Dauwalder 	}
10383f04694STyler Dauwalder };
10483f04694STyler Dauwalder #endif	// !TEST_R5
10583f04694STyler Dauwalder 
10683f04694STyler Dauwalder 
10783f04694STyler Dauwalder // setUp
10883f04694STyler Dauwalder void
setUp()10983f04694STyler Dauwalder RegistrarThreadManagerTest::setUp()
11083f04694STyler Dauwalder {
11183f04694STyler Dauwalder 	BTestCase::setUp();
11277b9927bSIngo Weinhold #ifndef TEST_R5
11383f04694STyler Dauwalder 	// Setup our application
11483f04694STyler Dauwalder 	fApplication = new BTestApp("application/x-vnd.obos.RegistrarThreadManagerTest");
11583f04694STyler Dauwalder 	if (fApplication->Init() != B_OK) {
116*2ca13760SColdfirex 		fprintf(stderr, "Failed to initialize application (perhaps the Haiku registrar isn't running?).\n");
11783f04694STyler Dauwalder 		delete fApplication;
11883f04694STyler Dauwalder 		fApplication = NULL;
11983f04694STyler Dauwalder 	}
12083f04694STyler Dauwalder #endif	// !TEST_R5
12183f04694STyler Dauwalder }
12283f04694STyler Dauwalder 
12383f04694STyler Dauwalder // tearDown
12483f04694STyler Dauwalder void
tearDown()12583f04694STyler Dauwalder RegistrarThreadManagerTest::tearDown()
12683f04694STyler Dauwalder {
12777b9927bSIngo Weinhold #ifndef TEST_R5
12883f04694STyler Dauwalder 	// Terminate the Application
12983f04694STyler Dauwalder 	if (fApplication) {
13083f04694STyler Dauwalder 		fApplication->Terminate();
13183f04694STyler Dauwalder 		delete fApplication;
13283f04694STyler Dauwalder 		fApplication = NULL;
13383f04694STyler Dauwalder 	}
13483f04694STyler Dauwalder #endif	// !TEST_R5
13583f04694STyler Dauwalder 	BTestCase::tearDown();
13683f04694STyler Dauwalder }
13783f04694STyler Dauwalder 
13883f04694STyler Dauwalder void
ShutdownTest()13983f04694STyler Dauwalder RegistrarThreadManagerTest::ShutdownTest()
14083f04694STyler Dauwalder {
14177b9927bSIngo Weinhold #ifdef TEST_R5
14283f04694STyler Dauwalder 	Outputf("(no tests performed for R5 version)\n");
14383f04694STyler Dauwalder #else
14483f04694STyler Dauwalder 	NextSubTest();
14583f04694STyler Dauwalder 	status_t err = B_OK;
14683f04694STyler Dauwalder 	NextSubTest();
14783f04694STyler Dauwalder 	RegistrarThreadManager manager;
14883f04694STyler Dauwalder 	NextSubTest();
14983f04694STyler Dauwalder 	CHK(fApplication && fApplication->InitCheck() == B_OK);
15083f04694STyler Dauwalder 	NextSubTest();
15183f04694STyler Dauwalder //	fApplication->AddHandler(&manager);
15283f04694STyler Dauwalder 	NextSubTest();
15383f04694STyler Dauwalder 	BMessenger managerMessenger(NULL, fApplication, &err);
15477b9927bSIngo Weinhold // TODO: Do something about this...
15577b9927bSIngo Weinhold if (err != B_OK) {
15677b9927bSIngo Weinhold fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
15777b9927bSIngo Weinhold "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
15877b9927bSIngo Weinhold "which is only linked against R5's libbe).\n");
15977b9927bSIngo Weinhold }
16083f04694STyler Dauwalder 	NextSubTest();
16183f04694STyler Dauwalder 	CHK(err == B_OK && managerMessenger.IsValid());
16283f04694STyler Dauwalder 	NextSubTest();
16383f04694STyler Dauwalder 
16483f04694STyler Dauwalder 	// Launch a bunch of threads
16583f04694STyler Dauwalder 	const uint termThreads = 2;
16683f04694STyler Dauwalder 	const uint niceThreads = 2;
16783f04694STyler Dauwalder 	const uint evilThreads = 2;
16883f04694STyler Dauwalder 
16983f04694STyler Dauwalder 	for (uint i = 0; i < termThreads; i++) {
17083f04694STyler Dauwalder 		NextSubTest();
17183f04694STyler Dauwalder 		char name[1024];
17283f04694STyler Dauwalder 		sprintf(name, "terminating #%d", i);
17383f04694STyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
17483f04694STyler Dauwalder 		CHK(thread != NULL);
17583f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
17683f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
17783f04694STyler Dauwalder 	}
17883f04694STyler Dauwalder 
17983f04694STyler Dauwalder 	for (uint i = 0; i < niceThreads; i++) {
18083f04694STyler Dauwalder 		NextSubTest();
18183f04694STyler Dauwalder 		char name[1024];
18283f04694STyler Dauwalder 		sprintf(name, "nice #%d", i);
18383f04694STyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
18483f04694STyler Dauwalder 		CHK(thread != NULL);
18583f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
18683f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
18783f04694STyler Dauwalder 	}
18883f04694STyler Dauwalder 
18983f04694STyler Dauwalder 	for (uint i = 0; i < evilThreads; i++) {
19083f04694STyler Dauwalder 		NextSubTest();
19183f04694STyler Dauwalder 		char name[1024];
19283f04694STyler Dauwalder 		sprintf(name, "evil #%d", i);
19383f04694STyler Dauwalder 		RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
19483f04694STyler Dauwalder 		CHK(thread != NULL);
19583f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
19683f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
19783f04694STyler Dauwalder 	}
19883f04694STyler Dauwalder 
19983f04694STyler Dauwalder 	// Check the number of threads before doing a cleanup
20083f04694STyler Dauwalder 	NextSubTest();	// <= 13
20183f04694STyler Dauwalder 	CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads));
20283f04694STyler Dauwalder 
20383f04694STyler Dauwalder 	// Do the cleanup and check again (the terminating threads
20483f04694STyler Dauwalder 	// should be gone)
20583f04694STyler Dauwalder 	NextSubTest();
20683f04694STyler Dauwalder 	snooze(500000);		// give them time to terminate
20783f04694STyler Dauwalder 	CHK(manager.CleanupThreads() == B_OK);
20883f04694STyler Dauwalder 	CHK(manager.ThreadCount() == (niceThreads + evilThreads));
20983f04694STyler Dauwalder 
21083f04694STyler Dauwalder 	// Now do a shutdown and check again (the nice infinite threads
21183f04694STyler Dauwalder 	// should be gone)
21283f04694STyler Dauwalder 	NextSubTest();
21383f04694STyler Dauwalder 	CHK(manager.ShutdownThreads() == B_OK);
21483f04694STyler Dauwalder 	snooze(1000000);	// give them time to quit nicely
21583f04694STyler Dauwalder 	CHK(manager.CleanupThreads() == B_OK);
21683f04694STyler Dauwalder 	CHK(manager.ThreadCount() == evilThreads);
21783f04694STyler Dauwalder 
21883f04694STyler Dauwalder 
21983f04694STyler Dauwalder 	// Now finally kill any remaining threads (which should rid us of
22083f04694STyler Dauwalder 	// the naughty infinite threads)
22183f04694STyler Dauwalder 	NextSubTest();
22283f04694STyler Dauwalder 	CHK(manager.KillThreads() == B_OK);
22383f04694STyler Dauwalder 	CHK(manager.ThreadCount() == 0);
22483f04694STyler Dauwalder 
22583f04694STyler Dauwalder #endif	// !TEST_R5
22683f04694STyler Dauwalder }
22783f04694STyler Dauwalder 
228cc24797bSTyler Dauwalder void
ThreadLimitTest()229cc24797bSTyler Dauwalder RegistrarThreadManagerTest::ThreadLimitTest()
230cc24797bSTyler Dauwalder {
23177b9927bSIngo Weinhold #ifdef TEST_R5
232cc24797bSTyler Dauwalder 	Outputf("(no tests performed for R5 version)\n");
233cc24797bSTyler Dauwalder #else
234cc24797bSTyler Dauwalder 	NextSubTest();
235cc24797bSTyler Dauwalder 	status_t err = B_OK;
236cc24797bSTyler Dauwalder 	RegistrarThreadManager manager;
237cc24797bSTyler Dauwalder 	CHK(fApplication && fApplication->InitCheck() == B_OK);
238cc24797bSTyler Dauwalder 	BMessenger managerMessenger(NULL, fApplication, &err);
23977b9927bSIngo Weinhold // TODO: Do something about this...
24077b9927bSIngo Weinhold if (err != B_OK) {
24177b9927bSIngo Weinhold fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
24277b9927bSIngo Weinhold "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
24377b9927bSIngo Weinhold "which is only linked against R5's libbe).\n");
24477b9927bSIngo Weinhold }
245cc24797bSTyler Dauwalder 	CHK(err == B_OK && managerMessenger.IsValid());
246cc24797bSTyler Dauwalder 
247cc24797bSTyler Dauwalder 	const uint termThreads = 2;
248cc24797bSTyler Dauwalder 
249cc24797bSTyler Dauwalder 	// This test is only useful if the thread limit of the manager
250cc24797bSTyler Dauwalder 	// class is > kTermThreads
251cc24797bSTyler Dauwalder 	CHK(termThreads < RegistrarThreadManager::kThreadLimit);
252cc24797bSTyler Dauwalder 
253cc24797bSTyler Dauwalder 	// Launch some terminating threads
254cc24797bSTyler Dauwalder 	uint i;
255cc24797bSTyler Dauwalder 	for (i = 0; i < termThreads; i++) {
256cc24797bSTyler Dauwalder 		NextSubTest();
257cc24797bSTyler Dauwalder 		char name[1024];
258cc24797bSTyler Dauwalder 		sprintf(name, "terminating #%d", i);
259cc24797bSTyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
260cc24797bSTyler Dauwalder 		CHK(thread != NULL);
261cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
262cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
263cc24797bSTyler Dauwalder 	}
264cc24797bSTyler Dauwalder 
265cc24797bSTyler Dauwalder 	// Now fill up the manager with non-terminating threads
266cc24797bSTyler Dauwalder 	for (; i < RegistrarThreadManager::kThreadLimit; i++) {
267cc24797bSTyler Dauwalder 		NextSubTest();
268cc24797bSTyler Dauwalder 		char name[1024];
269cc24797bSTyler Dauwalder 		sprintf(name, "nice #%d", i);
270cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
271cc24797bSTyler Dauwalder 		CHK(thread != NULL);
272cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
273cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
274cc24797bSTyler Dauwalder 	}
275cc24797bSTyler Dauwalder 	CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit);
276cc24797bSTyler Dauwalder 
277cc24797bSTyler Dauwalder 	// Now try to launch just one more...
278cc24797bSTyler Dauwalder 	NextSubTest();
279cc24797bSTyler Dauwalder 	{
280cc24797bSTyler Dauwalder 		char *name = "hopeless thread";
281cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
282cc24797bSTyler Dauwalder 		CHK(thread != NULL);
283cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
284cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
285cc24797bSTyler Dauwalder 		delete thread;
286cc24797bSTyler Dauwalder 	}
287cc24797bSTyler Dauwalder 
288cc24797bSTyler Dauwalder 	// Now wait a little bit for our terminating threads to quit,
289cc24797bSTyler Dauwalder 	// cleanup after them, and make sure we can now launch that
290cc24797bSTyler Dauwalder 	// many threads again
291cc24797bSTyler Dauwalder 	NextSubTest();
292cc24797bSTyler Dauwalder 	snooze(500000);
293cc24797bSTyler Dauwalder 	manager.CleanupThreads();
294cc24797bSTyler Dauwalder 
295cc24797bSTyler Dauwalder 	for (i = 0; i < termThreads; i++) {
296cc24797bSTyler Dauwalder 		NextSubTest();
297cc24797bSTyler Dauwalder 		char name[1024];
298cc24797bSTyler Dauwalder 		sprintf(name, "2nd round nice #%d", i);
299cc24797bSTyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
300cc24797bSTyler Dauwalder 		CHK(thread != NULL);
301cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
302cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
303cc24797bSTyler Dauwalder 	}
304cc24797bSTyler Dauwalder 
305cc24797bSTyler Dauwalder 	// Now try once more to launch just one more...
306cc24797bSTyler Dauwalder 	NextSubTest();
307cc24797bSTyler Dauwalder 	{
308cc24797bSTyler Dauwalder 		char *name = "hopeless thread";
309cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
310cc24797bSTyler Dauwalder 		CHK(thread != NULL);
311cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
312cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
313cc24797bSTyler Dauwalder 		delete thread;
314cc24797bSTyler Dauwalder 	}
315cc24797bSTyler Dauwalder 
316cc24797bSTyler Dauwalder 	// Cleanup
317cc24797bSTyler Dauwalder 	NextSubTest();
318cc24797bSTyler Dauwalder 	manager.ShutdownThreads();
319cc24797bSTyler Dauwalder 	snooze(500000);
320cc24797bSTyler Dauwalder 
321cc24797bSTyler Dauwalder #endif	// !TEST_R5
322cc24797bSTyler Dauwalder }
323