michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http:mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TestHarness.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: enum { michael@0: TEST_CALL_VOID_ARG_VOID_RETURN, michael@0: TEST_CALL_VOID_ARG_NONVOID_RETURN, michael@0: TEST_CALL_NONVOID_ARG_VOID_RETURN, michael@0: TEST_CALL_NONVOID_ARG_NONVOID_RETURN, michael@0: TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT, michael@0: TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, michael@0: #ifdef HAVE_STDCALL michael@0: TEST_STDCALL_VOID_ARG_VOID_RETURN, michael@0: TEST_STDCALL_VOID_ARG_NONVOID_RETURN, michael@0: TEST_STDCALL_NONVOID_ARG_VOID_RETURN, michael@0: TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN, michael@0: TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, michael@0: #endif michael@0: TEST_CALL_NEWTHREAD_SUICIDAL, michael@0: MAX_TESTS michael@0: }; michael@0: michael@0: bool gRunnableExecuted[MAX_TESTS]; michael@0: michael@0: class nsFoo : public nsISupports { michael@0: NS_DECL_ISUPPORTS michael@0: nsresult DoFoo(bool* aBool) { michael@0: *aBool = true; michael@0: return NS_OK; michael@0: } michael@0: virtual ~nsFoo() {} michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS0(nsFoo) michael@0: michael@0: class TestSuicide : public nsRunnable { michael@0: NS_IMETHOD Run() { michael@0: // Runs first time on thread "Suicide", then dies on MainThread michael@0: if (!NS_IsMainThread()) { michael@0: mThread = do_GetCurrentThread(); michael@0: NS_DispatchToMainThread(this); michael@0: return NS_OK; michael@0: } michael@0: MOZ_ASSERT(mThread); michael@0: mThread->Shutdown(); michael@0: gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mThread; michael@0: }; michael@0: michael@0: class nsBar : public nsISupports { michael@0: NS_DECL_ISUPPORTS michael@0: virtual ~nsBar() {} michael@0: void DoBar1(void) { michael@0: gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true; michael@0: } michael@0: nsresult DoBar2(void) { michael@0: gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true; michael@0: return NS_OK; michael@0: } michael@0: void DoBar3(nsFoo* aFoo) { michael@0: aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]); michael@0: } michael@0: nsresult DoBar4(nsFoo* aFoo) { michael@0: return aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]); michael@0: } michael@0: void DoBar5(nsFoo* aFoo) { michael@0: if (aFoo) michael@0: gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; michael@0: } michael@0: nsresult DoBar6(char* aFoo) { michael@0: if (strlen(aFoo)) michael@0: gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true; michael@0: return NS_OK; michael@0: } michael@0: #ifdef HAVE_STDCALL michael@0: void __stdcall DoBar1std(void) { michael@0: gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true; michael@0: } michael@0: nsresult __stdcall DoBar2std(void) { michael@0: gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true; michael@0: return NS_OK; michael@0: } michael@0: void __stdcall DoBar3std(nsFoo* aFoo) { michael@0: aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]); michael@0: } michael@0: nsresult __stdcall DoBar4std(nsFoo* aFoo) { michael@0: return aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]); michael@0: } michael@0: void __stdcall DoBar5std(nsFoo* aFoo) { michael@0: if (aFoo) michael@0: gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; michael@0: } michael@0: nsresult __stdcall DoBar6std(char* aFoo) { michael@0: if (strlen(aFoo)) michael@0: gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS0(nsBar) michael@0: michael@0: int main(int argc, char** argv) michael@0: { michael@0: ScopedXPCOM xpcom("ThreadUtils"); michael@0: NS_ENSURE_FALSE(xpcom.failed(), 1); michael@0: michael@0: memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool)); michael@0: // Scope the smart ptrs so that the runnables need to hold on to whatever they need michael@0: { michael@0: nsRefPtr foo = new nsFoo(); michael@0: nsRefPtr bar = new nsBar(); michael@0: michael@0: // This pointer will be freed at the end of the block michael@0: // Do not dereference this pointer in the runnable method! michael@0: nsFoo * rawFoo = new nsFoo(); michael@0: michael@0: // Read only string. Dereferencing in runnable method to check this works. michael@0: char* message = (char*)"Test message"; michael@0: michael@0: NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr > michael@0: (bar, &nsBar::DoBar3, foo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr > michael@0: (bar, &nsBar::DoBar4, foo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar5, rawFoo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar6, message)); michael@0: #ifdef HAVE_STDCALL michael@0: NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr > michael@0: (bar, &nsBar::DoBar3std, foo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr > michael@0: (bar, &nsBar::DoBar4std, foo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar5std, rawFoo)); michael@0: NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar6std, message)); michael@0: #endif michael@0: michael@0: delete rawFoo; michael@0: } michael@0: michael@0: // Spin the event loop michael@0: NS_ProcessPendingEvents(nullptr); michael@0: michael@0: // Now test a suicidal event in NS_New(Named)Thread michael@0: nsCOMPtr thread; michael@0: NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide()); michael@0: MOZ_ASSERT(thread); michael@0: michael@0: while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) { michael@0: NS_ProcessPendingEvents(nullptr); michael@0: } michael@0: michael@0: int result = 0; michael@0: michael@0: for (uint32_t i = 0; i < MAX_TESTS; i++) { michael@0: if (gRunnableExecuted[i]) { michael@0: passed("Test %d passed",i); michael@0: } else { michael@0: fail("Error in test %d", i); michael@0: result = 1; michael@0: } michael@0: } michael@0: michael@0: return result; michael@0: }