1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "mozilla/CondVar.h"
8 #include "mozilla/Monitor.h"
9 #include "mozilla/ReentrantMonitor.h"
10 #include "mozilla/Mutex.h"
11 #include "gtest/gtest.h"
12
13 using namespace mozilla;
14
15 static PRThread*
spawn(void (* run)(void *),void * arg)16 spawn(void (*run)(void*), void* arg)
17 {
18 return PR_CreateThread(PR_SYSTEM_THREAD,
19 run,
20 arg,
21 PR_PRIORITY_NORMAL,
22 PR_GLOBAL_THREAD,
23 PR_JOINABLE_THREAD,
24 0);
25 }
26
27 //-----------------------------------------------------------------------------
28 // Sanity check: tests that can be done on a single thread
29 //
TEST(Synchronization,Sanity)30 TEST(Synchronization, Sanity)
31 {
32 Mutex lock("sanity::lock");
33 lock.Lock();
34 lock.AssertCurrentThreadOwns();
35 lock.Unlock();
36
37 {
38 MutexAutoLock autolock(lock);
39 lock.AssertCurrentThreadOwns();
40 }
41
42 lock.Lock();
43 lock.AssertCurrentThreadOwns();
44 {
45 MutexAutoUnlock autounlock(lock);
46 }
47 lock.AssertCurrentThreadOwns();
48 lock.Unlock();
49
50 ReentrantMonitor mon("sanity::monitor");
51 mon.Enter();
52 mon.AssertCurrentThreadIn();
53 mon.Enter();
54 mon.AssertCurrentThreadIn();
55 mon.Exit();
56 mon.AssertCurrentThreadIn();
57 mon.Exit();
58
59 {
60 ReentrantMonitorAutoEnter automon(mon);
61 mon.AssertCurrentThreadIn();
62 }
63 }
64
65 //-----------------------------------------------------------------------------
66 // Mutex contention tests
67 //
68 static Mutex* gLock1;
69
70 static void
MutexContention_thread(void *)71 MutexContention_thread(void* /*arg*/)
72 {
73 for (int i = 0; i < 100000; ++i) {
74 gLock1->Lock();
75 gLock1->AssertCurrentThreadOwns();
76 gLock1->Unlock();
77 }
78 }
79
TEST(Synchronization,MutexContention)80 TEST(Synchronization, MutexContention)
81 {
82 gLock1 = new Mutex("lock1");
83 // PURPOSELY not checking for OOM. YAY!
84
85 PRThread* t1 = spawn(MutexContention_thread, nullptr);
86 PRThread* t2 = spawn(MutexContention_thread, nullptr);
87 PRThread* t3 = spawn(MutexContention_thread, nullptr);
88
89 PR_JoinThread(t1);
90 PR_JoinThread(t2);
91 PR_JoinThread(t3);
92
93 delete gLock1;
94 }
95
96 //-----------------------------------------------------------------------------
97 // Monitor tests
98 //
99 static Monitor* gMon1;
100
101 static void
MonitorContention_thread(void *)102 MonitorContention_thread(void* /*arg*/)
103 {
104 for (int i = 0; i < 100000; ++i) {
105 gMon1->Lock();
106 gMon1->AssertCurrentThreadOwns();
107 gMon1->Unlock();
108 }
109 }
110
TEST(Synchronization,MonitorContention)111 TEST(Synchronization, MonitorContention)
112 {
113 gMon1 = new Monitor("mon1");
114
115 PRThread* t1 = spawn(MonitorContention_thread, nullptr);
116 PRThread* t2 = spawn(MonitorContention_thread, nullptr);
117 PRThread* t3 = spawn(MonitorContention_thread, nullptr);
118
119 PR_JoinThread(t1);
120 PR_JoinThread(t2);
121 PR_JoinThread(t3);
122
123 delete gMon1;
124 }
125
126
127 static ReentrantMonitor* gMon2;
128
129 static void
MonitorContention2_thread(void *)130 MonitorContention2_thread(void* /*arg*/)
131 {
132 for (int i = 0; i < 100000; ++i) {
133 gMon2->Enter();
134 gMon2->AssertCurrentThreadIn();
135 {
136 gMon2->Enter();
137 gMon2->AssertCurrentThreadIn();
138 gMon2->Exit();
139 }
140 gMon2->AssertCurrentThreadIn();
141 gMon2->Exit();
142 }
143 }
144
TEST(Synchronization,MonitorContention2)145 TEST(Synchronization, MonitorContention2)
146 {
147 gMon2 = new ReentrantMonitor("mon1");
148
149 PRThread* t1 = spawn(MonitorContention2_thread, nullptr);
150 PRThread* t2 = spawn(MonitorContention2_thread, nullptr);
151 PRThread* t3 = spawn(MonitorContention2_thread, nullptr);
152
153 PR_JoinThread(t1);
154 PR_JoinThread(t2);
155 PR_JoinThread(t3);
156
157 delete gMon2;
158 }
159
160
161 static ReentrantMonitor* gMon3;
162 static int32_t gMonFirst;
163
164 static void
MonitorSyncSanity_thread(void *)165 MonitorSyncSanity_thread(void* /*arg*/)
166 {
167 gMon3->Enter();
168 gMon3->AssertCurrentThreadIn();
169 if (gMonFirst) {
170 gMonFirst = 0;
171 gMon3->Wait();
172 gMon3->Enter();
173 } else {
174 gMon3->Notify();
175 gMon3->Enter();
176 }
177 gMon3->AssertCurrentThreadIn();
178 gMon3->Exit();
179 gMon3->AssertCurrentThreadIn();
180 gMon3->Exit();
181 }
182
TEST(Synchronization,MonitorSyncSanity)183 TEST(Synchronization, MonitorSyncSanity)
184 {
185 gMon3 = new ReentrantMonitor("monitor::syncsanity");
186
187 for (int32_t i = 0; i < 10000; ++i) {
188 gMonFirst = 1;
189 PRThread* ping = spawn(MonitorSyncSanity_thread, nullptr);
190 PRThread* pong = spawn(MonitorSyncSanity_thread, nullptr);
191 PR_JoinThread(ping);
192 PR_JoinThread(pong);
193 }
194
195 delete gMon3;
196 }
197
198 //-----------------------------------------------------------------------------
199 // Condvar tests
200 //
201 static Mutex* gCvlock1;
202 static CondVar* gCv1;
203 static int32_t gCvFirst;
204
205 static void
CondVarSanity_thread(void *)206 CondVarSanity_thread(void* /*arg*/)
207 {
208 gCvlock1->Lock();
209 gCvlock1->AssertCurrentThreadOwns();
210 if (gCvFirst) {
211 gCvFirst = 0;
212 gCv1->Wait();
213 } else {
214 gCv1->Notify();
215 }
216 gCvlock1->AssertCurrentThreadOwns();
217 gCvlock1->Unlock();
218 }
219
TEST(Synchronization,CondVarSanity)220 TEST(Synchronization, CondVarSanity)
221 {
222 gCvlock1 = new Mutex("cvlock1");
223 gCv1 = new CondVar(*gCvlock1, "cvlock1");
224
225 for (int32_t i = 0; i < 10000; ++i) {
226 gCvFirst = 1;
227 PRThread* ping = spawn(CondVarSanity_thread, nullptr);
228 PRThread* pong = spawn(CondVarSanity_thread, nullptr);
229 PR_JoinThread(ping);
230 PR_JoinThread(pong);
231 }
232
233 delete gCv1;
234 delete gCvlock1;
235 }
236
237 //-----------------------------------------------------------------------------
238 // AutoLock tests
239 //
TEST(Synchronization,AutoLock)240 TEST(Synchronization, AutoLock)
241 {
242 Mutex l1("autolock");
243 MutexAutoLock autol1(l1);
244
245 l1.AssertCurrentThreadOwns();
246
247 {
248 Mutex l2("autolock2");
249 MutexAutoLock autol2(l2);
250
251 l1.AssertCurrentThreadOwns();
252 l2.AssertCurrentThreadOwns();
253 }
254
255 l1.AssertCurrentThreadOwns();
256 }
257
258 //-----------------------------------------------------------------------------
259 // AutoUnlock tests
260 //
TEST(Synchronization,AutoUnlock)261 TEST(Synchronization, AutoUnlock)
262 {
263 Mutex l1("autounlock");
264 Mutex l2("autounlock2");
265
266 l1.Lock();
267 l1.AssertCurrentThreadOwns();
268
269 {
270 MutexAutoUnlock autol1(l1);
271 {
272 l2.Lock();
273 l2.AssertCurrentThreadOwns();
274
275 MutexAutoUnlock autol2(l2);
276 }
277 l2.AssertCurrentThreadOwns();
278 l2.Unlock();
279 }
280 l1.AssertCurrentThreadOwns();
281
282 l1.Unlock();
283 }
284
285 //-----------------------------------------------------------------------------
286 // AutoMonitor tests
287 //
TEST(Synchronization,AutoMonitor)288 TEST(Synchronization, AutoMonitor)
289 {
290 ReentrantMonitor m1("automonitor");
291 ReentrantMonitor m2("automonitor2");
292
293 m1.Enter();
294 m1.AssertCurrentThreadIn();
295 {
296 ReentrantMonitorAutoEnter autom1(m1);
297 m1.AssertCurrentThreadIn();
298
299 m2.Enter();
300 m2.AssertCurrentThreadIn();
301 {
302 ReentrantMonitorAutoEnter autom2(m2);
303 m1.AssertCurrentThreadIn();
304 m2.AssertCurrentThreadIn();
305 }
306 m2.AssertCurrentThreadIn();
307 m2.Exit();
308
309 m1.AssertCurrentThreadIn();
310 }
311 m1.AssertCurrentThreadIn();
312 m1.Exit();
313 }
314