|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http:mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "TestHarness.h" |
|
6 #include "nsThreadUtils.h" |
|
7 |
|
8 enum { |
|
9 TEST_CALL_VOID_ARG_VOID_RETURN, |
|
10 TEST_CALL_VOID_ARG_NONVOID_RETURN, |
|
11 TEST_CALL_NONVOID_ARG_VOID_RETURN, |
|
12 TEST_CALL_NONVOID_ARG_NONVOID_RETURN, |
|
13 TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT, |
|
14 TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, |
|
15 #ifdef HAVE_STDCALL |
|
16 TEST_STDCALL_VOID_ARG_VOID_RETURN, |
|
17 TEST_STDCALL_VOID_ARG_NONVOID_RETURN, |
|
18 TEST_STDCALL_NONVOID_ARG_VOID_RETURN, |
|
19 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN, |
|
20 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT, |
|
21 #endif |
|
22 TEST_CALL_NEWTHREAD_SUICIDAL, |
|
23 MAX_TESTS |
|
24 }; |
|
25 |
|
26 bool gRunnableExecuted[MAX_TESTS]; |
|
27 |
|
28 class nsFoo : public nsISupports { |
|
29 NS_DECL_ISUPPORTS |
|
30 nsresult DoFoo(bool* aBool) { |
|
31 *aBool = true; |
|
32 return NS_OK; |
|
33 } |
|
34 virtual ~nsFoo() {} |
|
35 }; |
|
36 |
|
37 NS_IMPL_ISUPPORTS0(nsFoo) |
|
38 |
|
39 class TestSuicide : public nsRunnable { |
|
40 NS_IMETHOD Run() { |
|
41 // Runs first time on thread "Suicide", then dies on MainThread |
|
42 if (!NS_IsMainThread()) { |
|
43 mThread = do_GetCurrentThread(); |
|
44 NS_DispatchToMainThread(this); |
|
45 return NS_OK; |
|
46 } |
|
47 MOZ_ASSERT(mThread); |
|
48 mThread->Shutdown(); |
|
49 gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true; |
|
50 return NS_OK; |
|
51 } |
|
52 |
|
53 private: |
|
54 nsCOMPtr<nsIThread> mThread; |
|
55 }; |
|
56 |
|
57 class nsBar : public nsISupports { |
|
58 NS_DECL_ISUPPORTS |
|
59 virtual ~nsBar() {} |
|
60 void DoBar1(void) { |
|
61 gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true; |
|
62 } |
|
63 nsresult DoBar2(void) { |
|
64 gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true; |
|
65 return NS_OK; |
|
66 } |
|
67 void DoBar3(nsFoo* aFoo) { |
|
68 aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]); |
|
69 } |
|
70 nsresult DoBar4(nsFoo* aFoo) { |
|
71 return aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]); |
|
72 } |
|
73 void DoBar5(nsFoo* aFoo) { |
|
74 if (aFoo) |
|
75 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; |
|
76 } |
|
77 nsresult DoBar6(char* aFoo) { |
|
78 if (strlen(aFoo)) |
|
79 gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true; |
|
80 return NS_OK; |
|
81 } |
|
82 #ifdef HAVE_STDCALL |
|
83 void __stdcall DoBar1std(void) { |
|
84 gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true; |
|
85 } |
|
86 nsresult __stdcall DoBar2std(void) { |
|
87 gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true; |
|
88 return NS_OK; |
|
89 } |
|
90 void __stdcall DoBar3std(nsFoo* aFoo) { |
|
91 aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]); |
|
92 } |
|
93 nsresult __stdcall DoBar4std(nsFoo* aFoo) { |
|
94 return aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]); |
|
95 } |
|
96 void __stdcall DoBar5std(nsFoo* aFoo) { |
|
97 if (aFoo) |
|
98 gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; |
|
99 } |
|
100 nsresult __stdcall DoBar6std(char* aFoo) { |
|
101 if (strlen(aFoo)) |
|
102 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true; |
|
103 return NS_OK; |
|
104 } |
|
105 #endif |
|
106 }; |
|
107 |
|
108 NS_IMPL_ISUPPORTS0(nsBar) |
|
109 |
|
110 int main(int argc, char** argv) |
|
111 { |
|
112 ScopedXPCOM xpcom("ThreadUtils"); |
|
113 NS_ENSURE_FALSE(xpcom.failed(), 1); |
|
114 |
|
115 memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool)); |
|
116 // Scope the smart ptrs so that the runnables need to hold on to whatever they need |
|
117 { |
|
118 nsRefPtr<nsFoo> foo = new nsFoo(); |
|
119 nsRefPtr<nsBar> bar = new nsBar(); |
|
120 |
|
121 // This pointer will be freed at the end of the block |
|
122 // Do not dereference this pointer in the runnable method! |
|
123 nsFoo * rawFoo = new nsFoo(); |
|
124 |
|
125 // Read only string. Dereferencing in runnable method to check this works. |
|
126 char* message = (char*)"Test message"; |
|
127 |
|
128 NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1)); |
|
129 NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2)); |
|
130 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > |
|
131 (bar, &nsBar::DoBar3, foo)); |
|
132 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > |
|
133 (bar, &nsBar::DoBar4, foo)); |
|
134 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5, rawFoo)); |
|
135 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6, message)); |
|
136 #ifdef HAVE_STDCALL |
|
137 NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std)); |
|
138 NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std)); |
|
139 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > |
|
140 (bar, &nsBar::DoBar3std, foo)); |
|
141 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > |
|
142 (bar, &nsBar::DoBar4std, foo)); |
|
143 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo)); |
|
144 NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6std, message)); |
|
145 #endif |
|
146 |
|
147 delete rawFoo; |
|
148 } |
|
149 |
|
150 // Spin the event loop |
|
151 NS_ProcessPendingEvents(nullptr); |
|
152 |
|
153 // Now test a suicidal event in NS_New(Named)Thread |
|
154 nsCOMPtr<nsIThread> thread; |
|
155 NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide()); |
|
156 MOZ_ASSERT(thread); |
|
157 |
|
158 while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) { |
|
159 NS_ProcessPendingEvents(nullptr); |
|
160 } |
|
161 |
|
162 int result = 0; |
|
163 |
|
164 for (uint32_t i = 0; i < MAX_TESTS; i++) { |
|
165 if (gRunnableExecuted[i]) { |
|
166 passed("Test %d passed",i); |
|
167 } else { |
|
168 fail("Error in test %d", i); |
|
169 result = 1; |
|
170 } |
|
171 } |
|
172 |
|
173 return result; |
|
174 } |