1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestThreadUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,174 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 +* License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +* file, You can obtain one at http:mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "TestHarness.h" 1.9 +#include "nsThreadUtils.h" 1.10 + 1.11 +enum { 1.12 + TEST_CALL_VOID_ARG_VOID_RETURN, 1.13 + TEST_CALL_VOID_ARG_NONVOID_RETURN, 1.14 + TEST_CALL_NONVOID_ARG_VOID_RETURN, 1.15 + TEST_CALL_NONVOID_ARG_NONVOID_RETURN, 1.16 + TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT, 1.17 + TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, 1.18 +#ifdef HAVE_STDCALL 1.19 + TEST_STDCALL_VOID_ARG_VOID_RETURN, 1.20 + TEST_STDCALL_VOID_ARG_NONVOID_RETURN, 1.21 + TEST_STDCALL_NONVOID_ARG_VOID_RETURN, 1.22 + TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN, 1.23 + TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, 1.24 +#endif 1.25 + TEST_CALL_NEWTHREAD_SUICIDAL, 1.26 + MAX_TESTS 1.27 +}; 1.28 + 1.29 +bool gRunnableExecuted[MAX_TESTS]; 1.30 + 1.31 +class nsFoo : public nsISupports { 1.32 + NS_DECL_ISUPPORTS 1.33 + nsresult DoFoo(bool* aBool) { 1.34 + *aBool = true; 1.35 + return NS_OK; 1.36 + } 1.37 + virtual ~nsFoo() {} 1.38 +}; 1.39 + 1.40 +NS_IMPL_ISUPPORTS0(nsFoo) 1.41 + 1.42 +class TestSuicide : public nsRunnable { 1.43 + NS_IMETHOD Run() { 1.44 + // Runs first time on thread "Suicide", then dies on MainThread 1.45 + if (!NS_IsMainThread()) { 1.46 + mThread = do_GetCurrentThread(); 1.47 + NS_DispatchToMainThread(this); 1.48 + return NS_OK; 1.49 + } 1.50 + MOZ_ASSERT(mThread); 1.51 + mThread->Shutdown(); 1.52 + gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true; 1.53 + return NS_OK; 1.54 + } 1.55 + 1.56 +private: 1.57 + nsCOMPtr<nsIThread> mThread; 1.58 +}; 1.59 + 1.60 +class nsBar : public nsISupports { 1.61 + NS_DECL_ISUPPORTS 1.62 + virtual ~nsBar() {} 1.63 + void DoBar1(void) { 1.64 + gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true; 1.65 + } 1.66 + nsresult DoBar2(void) { 1.67 + gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true; 1.68 + return NS_OK; 1.69 + } 1.70 + void DoBar3(nsFoo* aFoo) { 1.71 + aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]); 1.72 + } 1.73 + nsresult DoBar4(nsFoo* aFoo) { 1.74 + return aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]); 1.75 + } 1.76 + void DoBar5(nsFoo* aFoo) { 1.77 + if (aFoo) 1.78 + gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; 1.79 + } 1.80 + nsresult DoBar6(char* aFoo) { 1.81 + if (strlen(aFoo)) 1.82 + gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true; 1.83 + return NS_OK; 1.84 + } 1.85 +#ifdef HAVE_STDCALL 1.86 + void __stdcall DoBar1std(void) { 1.87 + gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true; 1.88 + } 1.89 + nsresult __stdcall DoBar2std(void) { 1.90 + gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true; 1.91 + return NS_OK; 1.92 + } 1.93 + void __stdcall DoBar3std(nsFoo* aFoo) { 1.94 + aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]); 1.95 + } 1.96 + nsresult __stdcall DoBar4std(nsFoo* aFoo) { 1.97 + return aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]); 1.98 + } 1.99 + void __stdcall DoBar5std(nsFoo* aFoo) { 1.100 + if (aFoo) 1.101 + gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; 1.102 + } 1.103 + nsresult __stdcall DoBar6std(char* aFoo) { 1.104 + if (strlen(aFoo)) 1.105 + gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; 1.106 + return NS_OK; 1.107 + } 1.108 +#endif 1.109 +}; 1.110 + 1.111 +NS_IMPL_ISUPPORTS0(nsBar) 1.112 + 1.113 +int main(int argc, char** argv) 1.114 +{ 1.115 + ScopedXPCOM xpcom("ThreadUtils"); 1.116 + NS_ENSURE_FALSE(xpcom.failed(), 1); 1.117 + 1.118 + memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool)); 1.119 + // Scope the smart ptrs so that the runnables need to hold on to whatever they need 1.120 + { 1.121 + nsRefPtr<nsFoo> foo = new nsFoo(); 1.122 + nsRefPtr<nsBar> bar = new nsBar(); 1.123 + 1.124 + // This pointer will be freed at the end of the block 1.125 + // Do not dereference this pointer in the runnable method! 1.126 + nsFoo * rawFoo = new nsFoo(); 1.127 + 1.128 + // Read only string. Dereferencing in runnable method to check this works. 1.129 + char* message = (char*)"Test message"; 1.130 + 1.131 + NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1)); 1.132 + NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2)); 1.133 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > 1.134 + (bar, &nsBar::DoBar3, foo)); 1.135 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > 1.136 + (bar, &nsBar::DoBar4, foo)); 1.137 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5, rawFoo)); 1.138 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6, message)); 1.139 +#ifdef HAVE_STDCALL 1.140 + NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std)); 1.141 + NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std)); 1.142 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > 1.143 + (bar, &nsBar::DoBar3std, foo)); 1.144 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > 1.145 + (bar, &nsBar::DoBar4std, foo)); 1.146 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo)); 1.147 + NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6std, message)); 1.148 +#endif 1.149 + 1.150 + delete rawFoo; 1.151 + } 1.152 + 1.153 + // Spin the event loop 1.154 + NS_ProcessPendingEvents(nullptr); 1.155 + 1.156 + // Now test a suicidal event in NS_New(Named)Thread 1.157 + nsCOMPtr<nsIThread> thread; 1.158 + NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide()); 1.159 + MOZ_ASSERT(thread); 1.160 + 1.161 + while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) { 1.162 + NS_ProcessPendingEvents(nullptr); 1.163 + } 1.164 + 1.165 + int result = 0; 1.166 + 1.167 + for (uint32_t i = 0; i < MAX_TESTS; i++) { 1.168 + if (gRunnableExecuted[i]) { 1.169 + passed("Test %d passed",i); 1.170 + } else { 1.171 + fail("Error in test %d", i); 1.172 + result = 1; 1.173 + } 1.174 + } 1.175 + 1.176 + return result; 1.177 +}