CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / xpcom / tests / TestSynchronization.cpp
blob2fe84b3205a628f7567ac1c34b30b5000439760e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Chris Jones <jones.chris.g@gmail.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "TestHarness.h"
42 #include "mozilla/CondVar.h"
43 #include "mozilla/Monitor.h"
44 #include "mozilla/Mutex.h"
45 #include "nsAutoLock.h"
47 using namespace mozilla;
49 static PRThread*
50 spawn(void (*run)(void*), void* arg)
52 return PR_CreateThread(PR_SYSTEM_THREAD,
53 run,
54 arg,
55 PR_PRIORITY_NORMAL,
56 PR_GLOBAL_THREAD,
57 PR_JOINABLE_THREAD,
58 0);
62 #define PASS() \
63 do { \
64 passed(__FUNCTION__); \
65 return NS_OK; \
66 } while (0)
68 #define FAIL(why) \
69 do { \
70 fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
71 return NS_ERROR_FAILURE; \
72 } while (0)
74 //-----------------------------------------------------------------------------
75 // Sanity check: tests that can be done on a single thread
77 static nsresult
78 Sanity()
80 Mutex lock("sanity::lock");
81 lock.Lock();
82 lock.AssertCurrentThreadOwns();
83 lock.Unlock();
86 MutexAutoLock autolock(lock);
87 lock.AssertCurrentThreadOwns();
90 lock.Lock();
91 lock.AssertCurrentThreadOwns();
93 MutexAutoUnlock autounlock(lock);
95 lock.AssertCurrentThreadOwns();
96 lock.Unlock();
98 Monitor mon("sanity::monitor");
99 mon.Enter();
100 mon.AssertCurrentThreadIn();
101 mon.Enter();
102 mon.AssertCurrentThreadIn();
103 mon.Exit();
104 mon.AssertCurrentThreadIn();
105 mon.Exit();
108 MonitorAutoEnter automon(mon);
109 mon.AssertCurrentThreadIn();
112 PASS();
115 //-----------------------------------------------------------------------------
116 // Mutex contention tests
118 static Mutex* gLock1;
120 static void
121 MutexContention_thread(void* /*arg*/)
123 for (int i = 0; i < 100000; ++i) {
124 gLock1->Lock();
125 gLock1->AssertCurrentThreadOwns();
126 gLock1->Unlock();
130 static nsresult
131 MutexContention()
133 gLock1 = new Mutex("lock1");
134 // PURPOSELY not checking for OOM. YAY!
136 PRThread* t1 = spawn(MutexContention_thread, nsnull);
137 PRThread* t2 = spawn(MutexContention_thread, nsnull);
138 PRThread* t3 = spawn(MutexContention_thread, nsnull);
140 PR_JoinThread(t1);
141 PR_JoinThread(t2);
142 PR_JoinThread(t3);
144 delete gLock1;
146 PASS();
149 //-----------------------------------------------------------------------------
150 // Monitor tests
152 static Monitor* gMon1;
154 static void
155 MonitorContention_thread(void* /*arg*/)
157 for (int i = 0; i < 100000; ++i) {
158 gMon1->Enter();
159 gMon1->AssertCurrentThreadIn();
160 gMon1->Exit();
164 static nsresult
165 MonitorContention()
167 gMon1 = new Monitor("mon1");
169 PRThread* t1 = spawn(MonitorContention_thread, nsnull);
170 PRThread* t2 = spawn(MonitorContention_thread, nsnull);
171 PRThread* t3 = spawn(MonitorContention_thread, nsnull);
173 PR_JoinThread(t1);
174 PR_JoinThread(t2);
175 PR_JoinThread(t3);
177 delete gMon1;
179 PASS();
183 static Monitor* gMon2;
185 static void
186 MonitorContention2_thread(void* /*arg*/)
188 for (int i = 0; i < 100000; ++i) {
189 gMon2->Enter();
190 gMon2->AssertCurrentThreadIn();
192 gMon2->Enter();
193 gMon2->AssertCurrentThreadIn();
194 gMon2->Exit();
196 gMon2->AssertCurrentThreadIn();
197 gMon2->Exit();
201 static nsresult
202 MonitorContention2()
204 gMon2 = new Monitor("mon1");
206 PRThread* t1 = spawn(MonitorContention2_thread, nsnull);
207 PRThread* t2 = spawn(MonitorContention2_thread, nsnull);
208 PRThread* t3 = spawn(MonitorContention2_thread, nsnull);
210 PR_JoinThread(t1);
211 PR_JoinThread(t2);
212 PR_JoinThread(t3);
214 delete gMon2;
216 PASS();
220 static Monitor* gMon3;
221 static PRInt32 gMonFirst;
223 static void
224 MonitorSyncSanity_thread(void* /*arg*/)
226 gMon3->Enter();
227 gMon3->AssertCurrentThreadIn();
228 if (gMonFirst) {
229 gMonFirst = 0;
230 gMon3->Wait();
231 gMon3->Enter();
232 } else {
233 gMon3->Notify();
234 gMon3->Enter();
236 gMon3->AssertCurrentThreadIn();
237 gMon3->Exit();
238 gMon3->AssertCurrentThreadIn();
239 gMon3->Exit();
242 static nsresult
243 MonitorSyncSanity()
245 gMon3 = new Monitor("monitor::syncsanity");
247 for (PRInt32 i = 0; i < 10000; ++i) {
248 gMonFirst = 1;
249 PRThread* ping = spawn(MonitorSyncSanity_thread, nsnull);
250 PRThread* pong = spawn(MonitorSyncSanity_thread, nsnull);
251 PR_JoinThread(ping);
252 PR_JoinThread(pong);
255 delete gMon3;
257 PASS();
260 //-----------------------------------------------------------------------------
261 // Condvar tests
263 static Mutex* gCvlock1;
264 static CondVar* gCv1;
265 static PRInt32 gCvFirst;
267 static void
268 CondVarSanity_thread(void* /*arg*/)
270 gCvlock1->Lock();
271 gCvlock1->AssertCurrentThreadOwns();
272 if (gCvFirst) {
273 gCvFirst = 0;
274 gCv1->Wait();
275 } else {
276 gCv1->Notify();
278 gCvlock1->AssertCurrentThreadOwns();
279 gCvlock1->Unlock();
282 static nsresult
283 CondVarSanity()
285 gCvlock1 = new Mutex("cvlock1");
286 gCv1 = new CondVar(*gCvlock1, "cvlock1");
288 for (PRInt32 i = 0; i < 10000; ++i) {
289 gCvFirst = 1;
290 PRThread* ping = spawn(CondVarSanity_thread, nsnull);
291 PRThread* pong = spawn(CondVarSanity_thread, nsnull);
292 PR_JoinThread(ping);
293 PR_JoinThread(pong);
296 delete gCv1;
297 delete gCvlock1;
299 PASS();
302 //-----------------------------------------------------------------------------
303 // AutoLock tests
305 static nsresult
306 AutoLock()
308 Mutex l1("autolock");
309 MutexAutoLock autol1(l1);
311 l1.AssertCurrentThreadOwns();
314 Mutex l2("autolock2");
315 MutexAutoLock autol2(l2);
317 l1.AssertCurrentThreadOwns();
318 l2.AssertCurrentThreadOwns();
321 l1.AssertCurrentThreadOwns();
323 PASS();
326 //-----------------------------------------------------------------------------
327 // AutoUnlock tests
329 static nsresult
330 AutoUnlock()
332 Mutex l1("autounlock");
333 Mutex l2("autounlock2");
335 l1.Lock();
336 l1.AssertCurrentThreadOwns();
339 MutexAutoUnlock autol1(l1);
341 l2.Lock();
342 l2.AssertCurrentThreadOwns();
344 MutexAutoUnlock autol2(l2);
346 l2.AssertCurrentThreadOwns();
347 l2.Unlock();
349 l1.AssertCurrentThreadOwns();
351 l1.Unlock();
353 PASS();
356 //-----------------------------------------------------------------------------
357 // AutoMonitor tests
359 static nsresult
360 AutoMonitor()
362 Monitor m1("automonitor");
363 Monitor m2("automonitor2");
365 m1.Enter();
366 m1.AssertCurrentThreadIn();
368 MonitorAutoEnter autom1(m1);
369 m1.AssertCurrentThreadIn();
371 m2.Enter();
372 m2.AssertCurrentThreadIn();
374 MonitorAutoEnter autom2(m2);
375 m1.AssertCurrentThreadIn();
376 m2.AssertCurrentThreadIn();
378 m2.AssertCurrentThreadIn();
379 m2.Exit();
381 m1.AssertCurrentThreadIn();
383 m1.AssertCurrentThreadIn();
384 m1.Exit();
386 PASS();
389 //-----------------------------------------------------------------------------
392 main(int argc, char** argv)
394 ScopedXPCOM xpcom("Synchronization (" __FILE__ ")");
395 if (xpcom.failed())
396 return 1;
398 int rv = 0;
400 if (NS_FAILED(Sanity()))
401 rv = 1;
402 if (NS_FAILED(MutexContention()))
403 rv = 1;
404 if (NS_FAILED(MonitorContention()))
405 rv = 1;
406 if (NS_FAILED(MonitorContention2()))
407 rv = 1;
408 if (NS_FAILED(MonitorSyncSanity()))
409 rv = 1;
410 if (NS_FAILED(CondVarSanity()))
411 rv = 1;
412 if (NS_FAILED(AutoLock()))
413 rv = 1;
414 if (NS_FAILED(AutoUnlock()))
415 rv = 1;
416 if (NS_FAILED(AutoMonitor()))
417 rv = 1;
419 return rv;