xpcom/tests/TestSynchronization.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:bd7db0559eb0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "TestHarness.h"
8
9 #include "mozilla/CondVar.h"
10 #include "mozilla/Monitor.h"
11 #include "mozilla/Mutex.h"
12 #include "nsAutoLock.h"
13
14 using namespace mozilla;
15
16 static PRThread*
17 spawn(void (*run)(void*), void* arg)
18 {
19 return PR_CreateThread(PR_SYSTEM_THREAD,
20 run,
21 arg,
22 PR_PRIORITY_NORMAL,
23 PR_GLOBAL_THREAD,
24 PR_JOINABLE_THREAD,
25 0);
26 }
27
28
29 #define PASS() \
30 do { \
31 passed(__FUNCTION__); \
32 return NS_OK; \
33 } while (0)
34
35 #define FAIL(why) \
36 do { \
37 fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
38 return NS_ERROR_FAILURE; \
39 } while (0)
40
41 //-----------------------------------------------------------------------------
42 // Sanity check: tests that can be done on a single thread
43 //
44 static nsresult
45 Sanity()
46 {
47 Mutex lock("sanity::lock");
48 lock.Lock();
49 lock.AssertCurrentThreadOwns();
50 lock.Unlock();
51
52 {
53 MutexAutoLock autolock(lock);
54 lock.AssertCurrentThreadOwns();
55 }
56
57 lock.Lock();
58 lock.AssertCurrentThreadOwns();
59 {
60 MutexAutoUnlock autounlock(lock);
61 }
62 lock.AssertCurrentThreadOwns();
63 lock.Unlock();
64
65 Monitor mon("sanity::monitor");
66 mon.Enter();
67 mon.AssertCurrentThreadIn();
68 mon.Enter();
69 mon.AssertCurrentThreadIn();
70 mon.Exit();
71 mon.AssertCurrentThreadIn();
72 mon.Exit();
73
74 {
75 MonitorAutoEnter automon(mon);
76 mon.AssertCurrentThreadIn();
77 }
78
79 PASS();
80 }
81
82 //-----------------------------------------------------------------------------
83 // Mutex contention tests
84 //
85 static Mutex* gLock1;
86
87 static void
88 MutexContention_thread(void* /*arg*/)
89 {
90 for (int i = 0; i < 100000; ++i) {
91 gLock1->Lock();
92 gLock1->AssertCurrentThreadOwns();
93 gLock1->Unlock();
94 }
95 }
96
97 static nsresult
98 MutexContention()
99 {
100 gLock1 = new Mutex("lock1");
101 // PURPOSELY not checking for OOM. YAY!
102
103 PRThread* t1 = spawn(MutexContention_thread, nullptr);
104 PRThread* t2 = spawn(MutexContention_thread, nullptr);
105 PRThread* t3 = spawn(MutexContention_thread, nullptr);
106
107 PR_JoinThread(t1);
108 PR_JoinThread(t2);
109 PR_JoinThread(t3);
110
111 delete gLock1;
112
113 PASS();
114 }
115
116 //-----------------------------------------------------------------------------
117 // Monitor tests
118 //
119 static Monitor* gMon1;
120
121 static void
122 MonitorContention_thread(void* /*arg*/)
123 {
124 for (int i = 0; i < 100000; ++i) {
125 gMon1->Enter();
126 gMon1->AssertCurrentThreadIn();
127 gMon1->Exit();
128 }
129 }
130
131 static nsresult
132 MonitorContention()
133 {
134 gMon1 = new Monitor("mon1");
135
136 PRThread* t1 = spawn(MonitorContention_thread, nullptr);
137 PRThread* t2 = spawn(MonitorContention_thread, nullptr);
138 PRThread* t3 = spawn(MonitorContention_thread, nullptr);
139
140 PR_JoinThread(t1);
141 PR_JoinThread(t2);
142 PR_JoinThread(t3);
143
144 delete gMon1;
145
146 PASS();
147 }
148
149
150 static Monitor* gMon2;
151
152 static void
153 MonitorContention2_thread(void* /*arg*/)
154 {
155 for (int i = 0; i < 100000; ++i) {
156 gMon2->Enter();
157 gMon2->AssertCurrentThreadIn();
158 {
159 gMon2->Enter();
160 gMon2->AssertCurrentThreadIn();
161 gMon2->Exit();
162 }
163 gMon2->AssertCurrentThreadIn();
164 gMon2->Exit();
165 }
166 }
167
168 static nsresult
169 MonitorContention2()
170 {
171 gMon2 = new Monitor("mon1");
172
173 PRThread* t1 = spawn(MonitorContention2_thread, nullptr);
174 PRThread* t2 = spawn(MonitorContention2_thread, nullptr);
175 PRThread* t3 = spawn(MonitorContention2_thread, nullptr);
176
177 PR_JoinThread(t1);
178 PR_JoinThread(t2);
179 PR_JoinThread(t3);
180
181 delete gMon2;
182
183 PASS();
184 }
185
186
187 static Monitor* gMon3;
188 static int32_t gMonFirst;
189
190 static void
191 MonitorSyncSanity_thread(void* /*arg*/)
192 {
193 gMon3->Enter();
194 gMon3->AssertCurrentThreadIn();
195 if (gMonFirst) {
196 gMonFirst = 0;
197 gMon3->Wait();
198 gMon3->Enter();
199 } else {
200 gMon3->Notify();
201 gMon3->Enter();
202 }
203 gMon3->AssertCurrentThreadIn();
204 gMon3->Exit();
205 gMon3->AssertCurrentThreadIn();
206 gMon3->Exit();
207 }
208
209 static nsresult
210 MonitorSyncSanity()
211 {
212 gMon3 = new Monitor("monitor::syncsanity");
213
214 for (int32_t i = 0; i < 10000; ++i) {
215 gMonFirst = 1;
216 PRThread* ping = spawn(MonitorSyncSanity_thread, nullptr);
217 PRThread* pong = spawn(MonitorSyncSanity_thread, nullptr);
218 PR_JoinThread(ping);
219 PR_JoinThread(pong);
220 }
221
222 delete gMon3;
223
224 PASS();
225 }
226
227 //-----------------------------------------------------------------------------
228 // Condvar tests
229 //
230 static Mutex* gCvlock1;
231 static CondVar* gCv1;
232 static int32_t gCvFirst;
233
234 static void
235 CondVarSanity_thread(void* /*arg*/)
236 {
237 gCvlock1->Lock();
238 gCvlock1->AssertCurrentThreadOwns();
239 if (gCvFirst) {
240 gCvFirst = 0;
241 gCv1->Wait();
242 } else {
243 gCv1->Notify();
244 }
245 gCvlock1->AssertCurrentThreadOwns();
246 gCvlock1->Unlock();
247 }
248
249 static nsresult
250 CondVarSanity()
251 {
252 gCvlock1 = new Mutex("cvlock1");
253 gCv1 = new CondVar(*gCvlock1, "cvlock1");
254
255 for (int32_t i = 0; i < 10000; ++i) {
256 gCvFirst = 1;
257 PRThread* ping = spawn(CondVarSanity_thread, nullptr);
258 PRThread* pong = spawn(CondVarSanity_thread, nullptr);
259 PR_JoinThread(ping);
260 PR_JoinThread(pong);
261 }
262
263 delete gCv1;
264 delete gCvlock1;
265
266 PASS();
267 }
268
269 //-----------------------------------------------------------------------------
270 // AutoLock tests
271 //
272 static nsresult
273 AutoLock()
274 {
275 Mutex l1("autolock");
276 MutexAutoLock autol1(l1);
277
278 l1.AssertCurrentThreadOwns();
279
280 {
281 Mutex l2("autolock2");
282 MutexAutoLock autol2(l2);
283
284 l1.AssertCurrentThreadOwns();
285 l2.AssertCurrentThreadOwns();
286 }
287
288 l1.AssertCurrentThreadOwns();
289
290 PASS();
291 }
292
293 //-----------------------------------------------------------------------------
294 // AutoUnlock tests
295 //
296 static nsresult
297 AutoUnlock()
298 {
299 Mutex l1("autounlock");
300 Mutex l2("autounlock2");
301
302 l1.Lock();
303 l1.AssertCurrentThreadOwns();
304
305 {
306 MutexAutoUnlock autol1(l1);
307 {
308 l2.Lock();
309 l2.AssertCurrentThreadOwns();
310
311 MutexAutoUnlock autol2(l2);
312 }
313 l2.AssertCurrentThreadOwns();
314 l2.Unlock();
315 }
316 l1.AssertCurrentThreadOwns();
317
318 l1.Unlock();
319
320 PASS();
321 }
322
323 //-----------------------------------------------------------------------------
324 // AutoMonitor tests
325 //
326 static nsresult
327 AutoMonitor()
328 {
329 Monitor m1("automonitor");
330 Monitor m2("automonitor2");
331
332 m1.Enter();
333 m1.AssertCurrentThreadIn();
334 {
335 MonitorAutoEnter autom1(m1);
336 m1.AssertCurrentThreadIn();
337
338 m2.Enter();
339 m2.AssertCurrentThreadIn();
340 {
341 MonitorAutoEnter autom2(m2);
342 m1.AssertCurrentThreadIn();
343 m2.AssertCurrentThreadIn();
344 }
345 m2.AssertCurrentThreadIn();
346 m2.Exit();
347
348 m1.AssertCurrentThreadIn();
349 }
350 m1.AssertCurrentThreadIn();
351 m1.Exit();
352
353 PASS();
354 }
355
356 //-----------------------------------------------------------------------------
357
358 int
359 main(int argc, char** argv)
360 {
361 ScopedXPCOM xpcom("Synchronization (" __FILE__ ")");
362 if (xpcom.failed())
363 return 1;
364
365 int rv = 0;
366
367 if (NS_FAILED(Sanity()))
368 rv = 1;
369 if (NS_FAILED(MutexContention()))
370 rv = 1;
371 if (NS_FAILED(MonitorContention()))
372 rv = 1;
373 if (NS_FAILED(MonitorContention2()))
374 rv = 1;
375 if (NS_FAILED(MonitorSyncSanity()))
376 rv = 1;
377 if (NS_FAILED(CondVarSanity()))
378 rv = 1;
379 if (NS_FAILED(AutoLock()))
380 rv = 1;
381 if (NS_FAILED(AutoUnlock()))
382 rv = 1;
383 if (NS_FAILED(AutoMonitor()))
384 rv = 1;
385
386 return rv;
387 }

mercurial