xpcom/tests/TestThreadPoolListener.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:d0d2cbad2d3c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "TestHarness.h"
7
8 #include "nsIThread.h"
9 #include "nsIThreadPool.h"
10
11 #include "nsThreadUtils.h"
12 #include "nsXPCOMCIDInternal.h"
13 #include "pratom.h"
14 #include "prinrval.h"
15 #include "prmon.h"
16 #include "prthread.h"
17 #include "mozilla/Attributes.h"
18
19 #include "mozilla/ReentrantMonitor.h"
20 using namespace mozilla;
21
22 #define NUMBER_OF_THREADS 4
23
24 // One hour... because test boxes can be slow!
25 #define IDLE_THREAD_TIMEOUT 3600000
26
27 static nsIThread** gCreatedThreadList = nullptr;
28 static nsIThread** gShutDownThreadList = nullptr;
29
30 static ReentrantMonitor* gReentrantMonitor = nullptr;
31
32 static bool gAllRunnablesPosted = false;
33 static bool gAllThreadsCreated = false;
34 static bool gAllThreadsShutDown = false;
35
36 #ifdef DEBUG
37 #define TEST_ASSERTION(_test, _msg) \
38 NS_ASSERTION(_test, _msg);
39 #else
40 #define TEST_ASSERTION(_test, _msg) \
41 PR_BEGIN_MACRO \
42 if (!(_test)) { \
43 NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_test, __FILE__, __LINE__); \
44 } \
45 PR_END_MACRO
46 #endif
47
48 class Listener MOZ_FINAL : public nsIThreadPoolListener
49 {
50 public:
51 NS_DECL_THREADSAFE_ISUPPORTS
52 NS_DECL_NSITHREADPOOLLISTENER
53 };
54
55 NS_IMPL_ISUPPORTS(Listener, nsIThreadPoolListener)
56
57 NS_IMETHODIMP
58 Listener::OnThreadCreated()
59 {
60 nsCOMPtr<nsIThread> current(do_GetCurrentThread());
61 TEST_ASSERTION(current, "Couldn't get current thread!");
62
63 ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
64
65 while (!gAllRunnablesPosted) {
66 mon.Wait();
67 }
68
69 for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) {
70 nsIThread* thread = gCreatedThreadList[i];
71 TEST_ASSERTION(thread != current, "Saw the same thread twice!");
72
73 if (!thread) {
74 gCreatedThreadList[i] = current;
75 if (i == (NUMBER_OF_THREADS - 1)) {
76 gAllThreadsCreated = true;
77 mon.NotifyAll();
78 }
79 return NS_OK;
80 }
81 }
82
83 TEST_ASSERTION(false, "Too many threads!");
84 return NS_ERROR_FAILURE;
85 }
86
87 NS_IMETHODIMP
88 Listener::OnThreadShuttingDown()
89 {
90 nsCOMPtr<nsIThread> current(do_GetCurrentThread());
91 TEST_ASSERTION(current, "Couldn't get current thread!");
92
93 ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
94
95 for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) {
96 nsIThread* thread = gShutDownThreadList[i];
97 TEST_ASSERTION(thread != current, "Saw the same thread twice!");
98
99 if (!thread) {
100 gShutDownThreadList[i] = current;
101 if (i == (NUMBER_OF_THREADS - 1)) {
102 gAllThreadsShutDown = true;
103 mon.NotifyAll();
104 }
105 return NS_OK;
106 }
107 }
108
109 TEST_ASSERTION(false, "Too many threads!");
110 return NS_ERROR_FAILURE;
111 }
112
113 class AutoCreateAndDestroyReentrantMonitor
114 {
115 public:
116 AutoCreateAndDestroyReentrantMonitor(ReentrantMonitor** aReentrantMonitorPtr)
117 : mReentrantMonitorPtr(aReentrantMonitorPtr) {
118 *aReentrantMonitorPtr = new ReentrantMonitor("TestThreadPoolListener::AutoMon");
119 TEST_ASSERTION(*aReentrantMonitorPtr, "Out of memory!");
120 }
121
122 ~AutoCreateAndDestroyReentrantMonitor() {
123 if (*mReentrantMonitorPtr) {
124 delete *mReentrantMonitorPtr;
125 *mReentrantMonitorPtr = nullptr;
126 }
127 }
128
129 private:
130 ReentrantMonitor** mReentrantMonitorPtr;
131 };
132
133 int main(int argc, char** argv)
134 {
135 ScopedXPCOM xpcom("ThreadPoolListener");
136 NS_ENSURE_FALSE(xpcom.failed(), 1);
137
138 nsIThread* createdThreadList[NUMBER_OF_THREADS] = { nullptr };
139 gCreatedThreadList = createdThreadList;
140
141 nsIThread* shutDownThreadList[NUMBER_OF_THREADS] = { nullptr };
142 gShutDownThreadList = shutDownThreadList;
143
144 AutoCreateAndDestroyReentrantMonitor newMon(&gReentrantMonitor);
145 NS_ENSURE_TRUE(gReentrantMonitor, 1);
146
147 nsresult rv;
148
149 nsCOMPtr<nsIThreadPool> pool =
150 do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
151 NS_ENSURE_SUCCESS(rv, 1);
152
153 rv = pool->SetThreadLimit(NUMBER_OF_THREADS);
154 NS_ENSURE_SUCCESS(rv, 1);
155
156 rv = pool->SetIdleThreadLimit(NUMBER_OF_THREADS);
157 NS_ENSURE_SUCCESS(rv, 1);
158
159 rv = pool->SetIdleThreadTimeout(IDLE_THREAD_TIMEOUT);
160 NS_ENSURE_SUCCESS(rv, 1);
161
162 nsCOMPtr<nsIThreadPoolListener> listener = new Listener();
163 NS_ENSURE_TRUE(listener, 1);
164
165 rv = pool->SetListener(listener);
166 NS_ENSURE_SUCCESS(rv, 1);
167
168 {
169 ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
170
171 for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) {
172 nsCOMPtr<nsIRunnable> runnable = new nsRunnable();
173 NS_ENSURE_TRUE(runnable, 1);
174
175 rv = pool->Dispatch(runnable, NS_DISPATCH_NORMAL);
176 NS_ENSURE_SUCCESS(rv, 1);
177 }
178
179 gAllRunnablesPosted = true;
180 mon.NotifyAll();
181 }
182
183 {
184 ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
185 while (!gAllThreadsCreated) {
186 mon.Wait();
187 }
188 }
189
190 rv = pool->Shutdown();
191 NS_ENSURE_SUCCESS(rv, 1);
192
193 {
194 ReentrantMonitorAutoEnter mon(*gReentrantMonitor);
195 while (!gAllThreadsShutDown) {
196 mon.Wait();
197 }
198 }
199
200 for (uint32_t i = 0; i < NUMBER_OF_THREADS; i++) {
201 nsIThread* created = gCreatedThreadList[i];
202 NS_ENSURE_TRUE(created, 1);
203
204 bool match = false;
205 for (uint32_t j = 0; j < NUMBER_OF_THREADS; j++) {
206 nsIThread* destroyed = gShutDownThreadList[j];
207 NS_ENSURE_TRUE(destroyed, 1);
208
209 if (destroyed == created) {
210 match = true;
211 break;
212 }
213 }
214
215 NS_ENSURE_TRUE(match, 1);
216 }
217
218 return 0;
219 }

mercurial