xref: /haiku/src/tests/kits/app/RegistrarThreadManagerTest.cpp (revision cc24797b03cb9cf5da990c8768c48abbb82012df)
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 
983f04694STyler Dauwalder #if !TEST_R5
1083f04694STyler Dauwalder #include <RegistrarThread.h>
1183f04694STyler Dauwalder #include <RegistrarThreadManager.h>
1283f04694STyler Dauwalder #endif	// !TEST_R5
1383f04694STyler Dauwalder 
1483f04694STyler Dauwalder #include <stdio.h>
1583f04694STyler Dauwalder 
1683f04694STyler Dauwalder // Suite
1783f04694STyler Dauwalder CppUnit::Test*
1883f04694STyler Dauwalder RegistrarThreadManagerTest::Suite() {
1983f04694STyler Dauwalder 	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
2083f04694STyler Dauwalder 	typedef CppUnit::TestCaller<RegistrarThreadManagerTest> TC;
2183f04694STyler Dauwalder 
22*cc24797bSTyler Dauwalder 	suite->addTest( new TC("RegistrarThreadManager::Shutdown Test",
2383f04694STyler Dauwalder 						   &RegistrarThreadManagerTest::ShutdownTest) );
24*cc24797bSTyler Dauwalder 	suite->addTest( new TC("RegistrarThreadManager::Thread Limit Test",
25*cc24797bSTyler Dauwalder 						   &RegistrarThreadManagerTest::ThreadLimitTest) );
2683f04694STyler Dauwalder 
2783f04694STyler Dauwalder 
2883f04694STyler Dauwalder 	return suite;
2983f04694STyler Dauwalder }
3083f04694STyler Dauwalder 
3183f04694STyler Dauwalder #if !TEST_R5
3283f04694STyler Dauwalder // Base test thread class
3383f04694STyler Dauwalder class TestThread : public RegistrarThread {
3483f04694STyler Dauwalder public:
3583f04694STyler Dauwalder 	TestThread(const char *name, int32 priority, BMessenger managerMessenger)
3683f04694STyler Dauwalder 		: RegistrarThread(name, priority, managerMessenger)
3783f04694STyler Dauwalder 	{
3883f04694STyler Dauwalder 	}
3983f04694STyler Dauwalder 
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:
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:
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:
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:
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:
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:
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
10983f04694STyler Dauwalder RegistrarThreadManagerTest::setUp()
11083f04694STyler Dauwalder {
11183f04694STyler Dauwalder 	BTestCase::setUp();
11283f04694STyler Dauwalder #if !TEST_R5
11383f04694STyler Dauwalder 	// Setup our application
11483f04694STyler Dauwalder 	fApplication = new BTestApp("application/x-vnd.obos.RegistrarThreadManagerTest");
11583f04694STyler Dauwalder 	if (fApplication->Init() != B_OK) {
11683f04694STyler Dauwalder 		fprintf(stderr, "Failed to initialize application (perhaps the obos 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
12583f04694STyler Dauwalder RegistrarThreadManagerTest::tearDown()
12683f04694STyler Dauwalder {
12783f04694STyler Dauwalder #if !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
13983f04694STyler Dauwalder RegistrarThreadManagerTest::ShutdownTest()
14083f04694STyler Dauwalder {
14183f04694STyler Dauwalder #if 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);
15483f04694STyler Dauwalder 	NextSubTest();
15583f04694STyler Dauwalder 	CHK(err == B_OK && managerMessenger.IsValid());
15683f04694STyler Dauwalder 	NextSubTest();
15783f04694STyler Dauwalder 
15883f04694STyler Dauwalder 	// Launch a bunch of threads
15983f04694STyler Dauwalder 	const uint termThreads = 2;
16083f04694STyler Dauwalder 	const uint niceThreads = 2;
16183f04694STyler Dauwalder 	const uint evilThreads = 2;
16283f04694STyler Dauwalder 
16383f04694STyler Dauwalder 	for (uint i = 0; i < termThreads; i++) {
16483f04694STyler Dauwalder 		NextSubTest();
16583f04694STyler Dauwalder 		char name[1024];
16683f04694STyler Dauwalder 		sprintf(name, "terminating #%d", i);
16783f04694STyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
16883f04694STyler Dauwalder 		CHK(thread != NULL);
16983f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
17083f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
17183f04694STyler Dauwalder 	}
17283f04694STyler Dauwalder 
17383f04694STyler Dauwalder 	for (uint i = 0; i < niceThreads; i++) {
17483f04694STyler Dauwalder 		NextSubTest();
17583f04694STyler Dauwalder 		char name[1024];
17683f04694STyler Dauwalder 		sprintf(name, "nice #%d", i);
17783f04694STyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
17883f04694STyler Dauwalder 		CHK(thread != NULL);
17983f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
18083f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
18183f04694STyler Dauwalder 	}
18283f04694STyler Dauwalder 
18383f04694STyler Dauwalder 	for (uint i = 0; i < evilThreads; i++) {
18483f04694STyler Dauwalder 		NextSubTest();
18583f04694STyler Dauwalder 		char name[1024];
18683f04694STyler Dauwalder 		sprintf(name, "evil #%d", i);
18783f04694STyler Dauwalder 		RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
18883f04694STyler Dauwalder 		CHK(thread != NULL);
18983f04694STyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
19083f04694STyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
19183f04694STyler Dauwalder 	}
19283f04694STyler Dauwalder 
19383f04694STyler Dauwalder 	// Check the number of threads before doing a cleanup
19483f04694STyler Dauwalder 	NextSubTest();	// <= 13
19583f04694STyler Dauwalder 	CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads));
19683f04694STyler Dauwalder 
19783f04694STyler Dauwalder 	// Do the cleanup and check again (the terminating threads
19883f04694STyler Dauwalder 	// should be gone)
19983f04694STyler Dauwalder 	NextSubTest();
20083f04694STyler Dauwalder 	snooze(500000);		// give them time to terminate
20183f04694STyler Dauwalder 	CHK(manager.CleanupThreads() == B_OK);
20283f04694STyler Dauwalder 	CHK(manager.ThreadCount() == (niceThreads + evilThreads));
20383f04694STyler Dauwalder 
20483f04694STyler Dauwalder 	// Now do a shutdown and check again (the nice infinite threads
20583f04694STyler Dauwalder 	// should be gone)
20683f04694STyler Dauwalder 	NextSubTest();
20783f04694STyler Dauwalder 	CHK(manager.ShutdownThreads() == B_OK);
20883f04694STyler Dauwalder 	snooze(1000000);	// give them time to quit nicely
20983f04694STyler Dauwalder 	CHK(manager.CleanupThreads() == B_OK);
21083f04694STyler Dauwalder 	CHK(manager.ThreadCount() == evilThreads);
21183f04694STyler Dauwalder 
21283f04694STyler Dauwalder 
21383f04694STyler Dauwalder 	// Now finally kill any remaining threads (which should rid us of
21483f04694STyler Dauwalder 	// the naughty infinite threads)
21583f04694STyler Dauwalder 	NextSubTest();
21683f04694STyler Dauwalder 	CHK(manager.KillThreads() == B_OK);
21783f04694STyler Dauwalder 	CHK(manager.ThreadCount() == 0);
21883f04694STyler Dauwalder 
21983f04694STyler Dauwalder #endif	// !TEST_R5
22083f04694STyler Dauwalder }
22183f04694STyler Dauwalder 
222*cc24797bSTyler Dauwalder void
223*cc24797bSTyler Dauwalder RegistrarThreadManagerTest::ThreadLimitTest()
224*cc24797bSTyler Dauwalder {
225*cc24797bSTyler Dauwalder #if TEST_R5
226*cc24797bSTyler Dauwalder 	Outputf("(no tests performed for R5 version)\n");
227*cc24797bSTyler Dauwalder #else
228*cc24797bSTyler Dauwalder 	NextSubTest();
229*cc24797bSTyler Dauwalder 	status_t err = B_OK;
230*cc24797bSTyler Dauwalder 	RegistrarThreadManager manager;
231*cc24797bSTyler Dauwalder 	CHK(fApplication && fApplication->InitCheck() == B_OK);
232*cc24797bSTyler Dauwalder 	BMessenger managerMessenger(NULL, fApplication, &err);
233*cc24797bSTyler Dauwalder 	CHK(err == B_OK && managerMessenger.IsValid());
234*cc24797bSTyler Dauwalder 
235*cc24797bSTyler Dauwalder 	const uint termThreads = 2;
236*cc24797bSTyler Dauwalder 
237*cc24797bSTyler Dauwalder 	// This test is only useful if the thread limit of the manager
238*cc24797bSTyler Dauwalder 	// class is > kTermThreads
239*cc24797bSTyler Dauwalder 	CHK(termThreads < RegistrarThreadManager::kThreadLimit);
240*cc24797bSTyler Dauwalder 
241*cc24797bSTyler Dauwalder 	// Launch some terminating threads
242*cc24797bSTyler Dauwalder 	uint i;
243*cc24797bSTyler Dauwalder 	for (i = 0; i < termThreads; i++) {
244*cc24797bSTyler Dauwalder 		NextSubTest();
245*cc24797bSTyler Dauwalder 		char name[1024];
246*cc24797bSTyler Dauwalder 		sprintf(name, "terminating #%d", i);
247*cc24797bSTyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
248*cc24797bSTyler Dauwalder 		CHK(thread != NULL);
249*cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
250*cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
251*cc24797bSTyler Dauwalder 	}
252*cc24797bSTyler Dauwalder 
253*cc24797bSTyler Dauwalder 	// Now fill up the manager with non-terminating threads
254*cc24797bSTyler Dauwalder 	for (; i < RegistrarThreadManager::kThreadLimit; i++) {
255*cc24797bSTyler Dauwalder 		NextSubTest();
256*cc24797bSTyler Dauwalder 		char name[1024];
257*cc24797bSTyler Dauwalder 		sprintf(name, "nice #%d", i);
258*cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
259*cc24797bSTyler Dauwalder 		CHK(thread != NULL);
260*cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
261*cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
262*cc24797bSTyler Dauwalder 	}
263*cc24797bSTyler Dauwalder 	CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit);
264*cc24797bSTyler Dauwalder 
265*cc24797bSTyler Dauwalder 	// Now try to launch just one more...
266*cc24797bSTyler Dauwalder 	NextSubTest();
267*cc24797bSTyler Dauwalder 	{
268*cc24797bSTyler Dauwalder 		char *name = "hopeless thread";
269*cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
270*cc24797bSTyler Dauwalder 		CHK(thread != NULL);
271*cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
272*cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
273*cc24797bSTyler Dauwalder 		delete thread;
274*cc24797bSTyler Dauwalder 	}
275*cc24797bSTyler Dauwalder 
276*cc24797bSTyler Dauwalder 	// Now wait a little bit for our terminating threads to quit,
277*cc24797bSTyler Dauwalder 	// cleanup after them, and make sure we can now launch that
278*cc24797bSTyler Dauwalder 	// many threads again
279*cc24797bSTyler Dauwalder 	NextSubTest();
280*cc24797bSTyler Dauwalder 	snooze(500000);
281*cc24797bSTyler Dauwalder 	manager.CleanupThreads();
282*cc24797bSTyler Dauwalder 
283*cc24797bSTyler Dauwalder 	for (i = 0; i < termThreads; i++) {
284*cc24797bSTyler Dauwalder 		NextSubTest();
285*cc24797bSTyler Dauwalder 		char name[1024];
286*cc24797bSTyler Dauwalder 		sprintf(name, "2nd round nice #%d", i);
287*cc24797bSTyler Dauwalder 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
288*cc24797bSTyler Dauwalder 		CHK(thread != NULL);
289*cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
290*cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_OK);
291*cc24797bSTyler Dauwalder 	}
292*cc24797bSTyler Dauwalder 
293*cc24797bSTyler Dauwalder 	// Now try once more to launch just one more...
294*cc24797bSTyler Dauwalder 	NextSubTest();
295*cc24797bSTyler Dauwalder 	{
296*cc24797bSTyler Dauwalder 		char *name = "hopeless thread";
297*cc24797bSTyler Dauwalder 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
298*cc24797bSTyler Dauwalder 		CHK(thread != NULL);
299*cc24797bSTyler Dauwalder 		CHK(thread->InitCheck() == B_OK);
300*cc24797bSTyler Dauwalder 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
301*cc24797bSTyler Dauwalder 		delete thread;
302*cc24797bSTyler Dauwalder 	}
303*cc24797bSTyler Dauwalder 
304*cc24797bSTyler Dauwalder 	// Cleanup
305*cc24797bSTyler Dauwalder 	NextSubTest();
306*cc24797bSTyler Dauwalder 	manager.ShutdownThreads();
307*cc24797bSTyler Dauwalder 	snooze(500000);
308*cc24797bSTyler Dauwalder 
309*cc24797bSTyler Dauwalder #endif	// !TEST_R5
310*cc24797bSTyler Dauwalder }
311