1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestSynchronization.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,387 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: sw=4 ts=4 et : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "TestHarness.h" 1.11 + 1.12 +#include "mozilla/CondVar.h" 1.13 +#include "mozilla/Monitor.h" 1.14 +#include "mozilla/Mutex.h" 1.15 +#include "nsAutoLock.h" 1.16 + 1.17 +using namespace mozilla; 1.18 + 1.19 +static PRThread* 1.20 +spawn(void (*run)(void*), void* arg) 1.21 +{ 1.22 + return PR_CreateThread(PR_SYSTEM_THREAD, 1.23 + run, 1.24 + arg, 1.25 + PR_PRIORITY_NORMAL, 1.26 + PR_GLOBAL_THREAD, 1.27 + PR_JOINABLE_THREAD, 1.28 + 0); 1.29 +} 1.30 + 1.31 + 1.32 +#define PASS() \ 1.33 + do { \ 1.34 + passed(__FUNCTION__); \ 1.35 + return NS_OK; \ 1.36 + } while (0) 1.37 + 1.38 +#define FAIL(why) \ 1.39 + do { \ 1.40 + fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \ 1.41 + return NS_ERROR_FAILURE; \ 1.42 + } while (0) 1.43 + 1.44 +//----------------------------------------------------------------------------- 1.45 +// Sanity check: tests that can be done on a single thread 1.46 +// 1.47 +static nsresult 1.48 +Sanity() 1.49 +{ 1.50 + Mutex lock("sanity::lock"); 1.51 + lock.Lock(); 1.52 + lock.AssertCurrentThreadOwns(); 1.53 + lock.Unlock(); 1.54 + 1.55 + { 1.56 + MutexAutoLock autolock(lock); 1.57 + lock.AssertCurrentThreadOwns(); 1.58 + } 1.59 + 1.60 + lock.Lock(); 1.61 + lock.AssertCurrentThreadOwns(); 1.62 + { 1.63 + MutexAutoUnlock autounlock(lock); 1.64 + } 1.65 + lock.AssertCurrentThreadOwns(); 1.66 + lock.Unlock(); 1.67 + 1.68 + Monitor mon("sanity::monitor"); 1.69 + mon.Enter(); 1.70 + mon.AssertCurrentThreadIn(); 1.71 + mon.Enter(); 1.72 + mon.AssertCurrentThreadIn(); 1.73 + mon.Exit(); 1.74 + mon.AssertCurrentThreadIn(); 1.75 + mon.Exit(); 1.76 + 1.77 + { 1.78 + MonitorAutoEnter automon(mon); 1.79 + mon.AssertCurrentThreadIn(); 1.80 + } 1.81 + 1.82 + PASS(); 1.83 +} 1.84 + 1.85 +//----------------------------------------------------------------------------- 1.86 +// Mutex contention tests 1.87 +// 1.88 +static Mutex* gLock1; 1.89 + 1.90 +static void 1.91 +MutexContention_thread(void* /*arg*/) 1.92 +{ 1.93 + for (int i = 0; i < 100000; ++i) { 1.94 + gLock1->Lock(); 1.95 + gLock1->AssertCurrentThreadOwns(); 1.96 + gLock1->Unlock(); 1.97 + } 1.98 +} 1.99 + 1.100 +static nsresult 1.101 +MutexContention() 1.102 +{ 1.103 + gLock1 = new Mutex("lock1"); 1.104 + // PURPOSELY not checking for OOM. YAY! 1.105 + 1.106 + PRThread* t1 = spawn(MutexContention_thread, nullptr); 1.107 + PRThread* t2 = spawn(MutexContention_thread, nullptr); 1.108 + PRThread* t3 = spawn(MutexContention_thread, nullptr); 1.109 + 1.110 + PR_JoinThread(t1); 1.111 + PR_JoinThread(t2); 1.112 + PR_JoinThread(t3); 1.113 + 1.114 + delete gLock1; 1.115 + 1.116 + PASS(); 1.117 +} 1.118 + 1.119 +//----------------------------------------------------------------------------- 1.120 +// Monitor tests 1.121 +// 1.122 +static Monitor* gMon1; 1.123 + 1.124 +static void 1.125 +MonitorContention_thread(void* /*arg*/) 1.126 +{ 1.127 + for (int i = 0; i < 100000; ++i) { 1.128 + gMon1->Enter(); 1.129 + gMon1->AssertCurrentThreadIn(); 1.130 + gMon1->Exit(); 1.131 + } 1.132 +} 1.133 + 1.134 +static nsresult 1.135 +MonitorContention() 1.136 +{ 1.137 + gMon1 = new Monitor("mon1"); 1.138 + 1.139 + PRThread* t1 = spawn(MonitorContention_thread, nullptr); 1.140 + PRThread* t2 = spawn(MonitorContention_thread, nullptr); 1.141 + PRThread* t3 = spawn(MonitorContention_thread, nullptr); 1.142 + 1.143 + PR_JoinThread(t1); 1.144 + PR_JoinThread(t2); 1.145 + PR_JoinThread(t3); 1.146 + 1.147 + delete gMon1; 1.148 + 1.149 + PASS(); 1.150 +} 1.151 + 1.152 + 1.153 +static Monitor* gMon2; 1.154 + 1.155 +static void 1.156 +MonitorContention2_thread(void* /*arg*/) 1.157 +{ 1.158 + for (int i = 0; i < 100000; ++i) { 1.159 + gMon2->Enter(); 1.160 + gMon2->AssertCurrentThreadIn(); 1.161 + { 1.162 + gMon2->Enter(); 1.163 + gMon2->AssertCurrentThreadIn(); 1.164 + gMon2->Exit(); 1.165 + } 1.166 + gMon2->AssertCurrentThreadIn(); 1.167 + gMon2->Exit(); 1.168 + } 1.169 +} 1.170 + 1.171 +static nsresult 1.172 +MonitorContention2() 1.173 +{ 1.174 + gMon2 = new Monitor("mon1"); 1.175 + 1.176 + PRThread* t1 = spawn(MonitorContention2_thread, nullptr); 1.177 + PRThread* t2 = spawn(MonitorContention2_thread, nullptr); 1.178 + PRThread* t3 = spawn(MonitorContention2_thread, nullptr); 1.179 + 1.180 + PR_JoinThread(t1); 1.181 + PR_JoinThread(t2); 1.182 + PR_JoinThread(t3); 1.183 + 1.184 + delete gMon2; 1.185 + 1.186 + PASS(); 1.187 +} 1.188 + 1.189 + 1.190 +static Monitor* gMon3; 1.191 +static int32_t gMonFirst; 1.192 + 1.193 +static void 1.194 +MonitorSyncSanity_thread(void* /*arg*/) 1.195 +{ 1.196 + gMon3->Enter(); 1.197 + gMon3->AssertCurrentThreadIn(); 1.198 + if (gMonFirst) { 1.199 + gMonFirst = 0; 1.200 + gMon3->Wait(); 1.201 + gMon3->Enter(); 1.202 + } else { 1.203 + gMon3->Notify(); 1.204 + gMon3->Enter(); 1.205 + } 1.206 + gMon3->AssertCurrentThreadIn(); 1.207 + gMon3->Exit(); 1.208 + gMon3->AssertCurrentThreadIn(); 1.209 + gMon3->Exit(); 1.210 +} 1.211 + 1.212 +static nsresult 1.213 +MonitorSyncSanity() 1.214 +{ 1.215 + gMon3 = new Monitor("monitor::syncsanity"); 1.216 + 1.217 + for (int32_t i = 0; i < 10000; ++i) { 1.218 + gMonFirst = 1; 1.219 + PRThread* ping = spawn(MonitorSyncSanity_thread, nullptr); 1.220 + PRThread* pong = spawn(MonitorSyncSanity_thread, nullptr); 1.221 + PR_JoinThread(ping); 1.222 + PR_JoinThread(pong); 1.223 + } 1.224 + 1.225 + delete gMon3; 1.226 + 1.227 + PASS(); 1.228 +} 1.229 + 1.230 +//----------------------------------------------------------------------------- 1.231 +// Condvar tests 1.232 +// 1.233 +static Mutex* gCvlock1; 1.234 +static CondVar* gCv1; 1.235 +static int32_t gCvFirst; 1.236 + 1.237 +static void 1.238 +CondVarSanity_thread(void* /*arg*/) 1.239 +{ 1.240 + gCvlock1->Lock(); 1.241 + gCvlock1->AssertCurrentThreadOwns(); 1.242 + if (gCvFirst) { 1.243 + gCvFirst = 0; 1.244 + gCv1->Wait(); 1.245 + } else { 1.246 + gCv1->Notify(); 1.247 + } 1.248 + gCvlock1->AssertCurrentThreadOwns(); 1.249 + gCvlock1->Unlock(); 1.250 +} 1.251 + 1.252 +static nsresult 1.253 +CondVarSanity() 1.254 +{ 1.255 + gCvlock1 = new Mutex("cvlock1"); 1.256 + gCv1 = new CondVar(*gCvlock1, "cvlock1"); 1.257 + 1.258 + for (int32_t i = 0; i < 10000; ++i) { 1.259 + gCvFirst = 1; 1.260 + PRThread* ping = spawn(CondVarSanity_thread, nullptr); 1.261 + PRThread* pong = spawn(CondVarSanity_thread, nullptr); 1.262 + PR_JoinThread(ping); 1.263 + PR_JoinThread(pong); 1.264 + } 1.265 + 1.266 + delete gCv1; 1.267 + delete gCvlock1; 1.268 + 1.269 + PASS(); 1.270 +} 1.271 + 1.272 +//----------------------------------------------------------------------------- 1.273 +// AutoLock tests 1.274 +// 1.275 +static nsresult 1.276 +AutoLock() 1.277 +{ 1.278 + Mutex l1("autolock"); 1.279 + MutexAutoLock autol1(l1); 1.280 + 1.281 + l1.AssertCurrentThreadOwns(); 1.282 + 1.283 + { 1.284 + Mutex l2("autolock2"); 1.285 + MutexAutoLock autol2(l2); 1.286 + 1.287 + l1.AssertCurrentThreadOwns(); 1.288 + l2.AssertCurrentThreadOwns(); 1.289 + } 1.290 + 1.291 + l1.AssertCurrentThreadOwns(); 1.292 + 1.293 + PASS(); 1.294 +} 1.295 + 1.296 +//----------------------------------------------------------------------------- 1.297 +// AutoUnlock tests 1.298 +// 1.299 +static nsresult 1.300 +AutoUnlock() 1.301 +{ 1.302 + Mutex l1("autounlock"); 1.303 + Mutex l2("autounlock2"); 1.304 + 1.305 + l1.Lock(); 1.306 + l1.AssertCurrentThreadOwns(); 1.307 + 1.308 + { 1.309 + MutexAutoUnlock autol1(l1); 1.310 + { 1.311 + l2.Lock(); 1.312 + l2.AssertCurrentThreadOwns(); 1.313 + 1.314 + MutexAutoUnlock autol2(l2); 1.315 + } 1.316 + l2.AssertCurrentThreadOwns(); 1.317 + l2.Unlock(); 1.318 + } 1.319 + l1.AssertCurrentThreadOwns(); 1.320 + 1.321 + l1.Unlock(); 1.322 + 1.323 + PASS(); 1.324 +} 1.325 + 1.326 +//----------------------------------------------------------------------------- 1.327 +// AutoMonitor tests 1.328 +// 1.329 +static nsresult 1.330 +AutoMonitor() 1.331 +{ 1.332 + Monitor m1("automonitor"); 1.333 + Monitor m2("automonitor2"); 1.334 + 1.335 + m1.Enter(); 1.336 + m1.AssertCurrentThreadIn(); 1.337 + { 1.338 + MonitorAutoEnter autom1(m1); 1.339 + m1.AssertCurrentThreadIn(); 1.340 + 1.341 + m2.Enter(); 1.342 + m2.AssertCurrentThreadIn(); 1.343 + { 1.344 + MonitorAutoEnter autom2(m2); 1.345 + m1.AssertCurrentThreadIn(); 1.346 + m2.AssertCurrentThreadIn(); 1.347 + } 1.348 + m2.AssertCurrentThreadIn(); 1.349 + m2.Exit(); 1.350 + 1.351 + m1.AssertCurrentThreadIn(); 1.352 + } 1.353 + m1.AssertCurrentThreadIn(); 1.354 + m1.Exit(); 1.355 + 1.356 + PASS(); 1.357 +} 1.358 + 1.359 +//----------------------------------------------------------------------------- 1.360 + 1.361 +int 1.362 +main(int argc, char** argv) 1.363 +{ 1.364 + ScopedXPCOM xpcom("Synchronization (" __FILE__ ")"); 1.365 + if (xpcom.failed()) 1.366 + return 1; 1.367 + 1.368 + int rv = 0; 1.369 + 1.370 + if (NS_FAILED(Sanity())) 1.371 + rv = 1; 1.372 + if (NS_FAILED(MutexContention())) 1.373 + rv = 1; 1.374 + if (NS_FAILED(MonitorContention())) 1.375 + rv = 1; 1.376 + if (NS_FAILED(MonitorContention2())) 1.377 + rv = 1; 1.378 + if (NS_FAILED(MonitorSyncSanity())) 1.379 + rv = 1; 1.380 + if (NS_FAILED(CondVarSanity())) 1.381 + rv = 1; 1.382 + if (NS_FAILED(AutoLock())) 1.383 + rv = 1; 1.384 + if (NS_FAILED(AutoUnlock())) 1.385 + rv = 1; 1.386 + if (NS_FAILED(AutoMonitor())) 1.387 + rv = 1; 1.388 + 1.389 + return rv; 1.390 +}