storage/test/test_deadlock_detector.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: sw=4 ts=4 et :
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /**
michael@0 8 * Note: This file is a copy of xpcom/tests/TestDeadlockDetector.cpp, but all
michael@0 9 * mutexes were turned into SQLiteMutexes.
michael@0 10 */
michael@0 11
michael@0 12 #include "prenv.h"
michael@0 13 #include "prerror.h"
michael@0 14 #include "prio.h"
michael@0 15 #include "prproces.h"
michael@0 16
michael@0 17 #include "nsMemory.h"
michael@0 18
michael@0 19 #include "mozilla/CondVar.h"
michael@0 20 #include "mozilla/ReentrantMonitor.h"
michael@0 21 #include "SQLiteMutex.h"
michael@0 22
michael@0 23 #include "TestHarness.h"
michael@0 24
michael@0 25 using namespace mozilla;
michael@0 26
michael@0 27 /**
michael@0 28 * Helper class to allocate a sqlite3_mutex for our SQLiteMutex. Also makes
michael@0 29 * keeping the test files in sync easier.
michael@0 30 */
michael@0 31 class TestMutex : public mozilla::storage::SQLiteMutex
michael@0 32 {
michael@0 33 public:
michael@0 34 TestMutex(const char* aName)
michael@0 35 : mozilla::storage::SQLiteMutex(aName)
michael@0 36 , mInner(sqlite3_mutex_alloc(SQLITE_MUTEX_FAST))
michael@0 37 {
michael@0 38 NS_ASSERTION(mInner, "could not allocate a sqlite3_mutex");
michael@0 39 initWithMutex(mInner);
michael@0 40 }
michael@0 41
michael@0 42 ~TestMutex()
michael@0 43 {
michael@0 44 sqlite3_mutex_free(mInner);
michael@0 45 }
michael@0 46
michael@0 47 void Lock()
michael@0 48 {
michael@0 49 lock();
michael@0 50 }
michael@0 51
michael@0 52 void Unlock()
michael@0 53 {
michael@0 54 unlock();
michael@0 55 }
michael@0 56 private:
michael@0 57 sqlite3_mutex *mInner;
michael@0 58 };
michael@0 59
michael@0 60 static PRThread*
michael@0 61 spawn(void (*run)(void*), void* arg)
michael@0 62 {
michael@0 63 return PR_CreateThread(PR_SYSTEM_THREAD,
michael@0 64 run,
michael@0 65 arg,
michael@0 66 PR_PRIORITY_NORMAL,
michael@0 67 PR_GLOBAL_THREAD,
michael@0 68 PR_JOINABLE_THREAD,
michael@0 69 0);
michael@0 70 }
michael@0 71
michael@0 72 #define PASS() \
michael@0 73 do { \
michael@0 74 passed(__FUNCTION__); \
michael@0 75 return NS_OK; \
michael@0 76 } while (0)
michael@0 77
michael@0 78 #define FAIL(why) \
michael@0 79 do { \
michael@0 80 fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
michael@0 81 return NS_ERROR_FAILURE; \
michael@0 82 } while (0)
michael@0 83
michael@0 84 //-----------------------------------------------------------------------------
michael@0 85
michael@0 86 static const char* sPathToThisBinary;
michael@0 87 static const char* sAssertBehaviorEnv = "XPCOM_DEBUG_BREAK=abort";
michael@0 88
michael@0 89 class Subprocess
michael@0 90 {
michael@0 91 public:
michael@0 92 // not available until process finishes
michael@0 93 int32_t mExitCode;
michael@0 94 nsCString mStdout;
michael@0 95 nsCString mStderr;
michael@0 96
michael@0 97 Subprocess(const char* aTestName) {
michael@0 98 // set up stdio redirection
michael@0 99 PRFileDesc* readStdin; PRFileDesc* writeStdin;
michael@0 100 PRFileDesc* readStdout; PRFileDesc* writeStdout;
michael@0 101 PRFileDesc* readStderr; PRFileDesc* writeStderr;
michael@0 102 PRProcessAttr* pattr = PR_NewProcessAttr();
michael@0 103
michael@0 104 NS_ASSERTION(pattr, "couldn't allocate process attrs");
michael@0 105
michael@0 106 NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStdin, &writeStdin),
michael@0 107 "couldn't create child stdin pipe");
michael@0 108 NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(readStdin, true),
michael@0 109 "couldn't set child stdin inheritable");
michael@0 110 PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardInput, readStdin);
michael@0 111
michael@0 112 NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStdout, &writeStdout),
michael@0 113 "couldn't create child stdout pipe");
michael@0 114 NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(writeStdout, true),
michael@0 115 "couldn't set child stdout inheritable");
michael@0 116 PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardOutput, writeStdout);
michael@0 117
michael@0 118 NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStderr, &writeStderr),
michael@0 119 "couldn't create child stderr pipe");
michael@0 120 NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(writeStderr, true),
michael@0 121 "couldn't set child stderr inheritable");
michael@0 122 PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardError, writeStderr);
michael@0 123
michael@0 124 // set up argv with test name to run
michael@0 125 char* const newArgv[3] = {
michael@0 126 strdup(sPathToThisBinary),
michael@0 127 strdup(aTestName),
michael@0 128 0
michael@0 129 };
michael@0 130
michael@0 131 // make sure the child will abort if an assertion fails
michael@0 132 NS_ASSERTION(PR_SUCCESS == PR_SetEnv(sAssertBehaviorEnv),
michael@0 133 "couldn't set XPCOM_DEBUG_BREAK env var");
michael@0 134
michael@0 135 PRProcess* proc;
michael@0 136 NS_ASSERTION(proc = PR_CreateProcess(sPathToThisBinary,
michael@0 137 newArgv,
michael@0 138 0, // inherit environment
michael@0 139 pattr),
michael@0 140 "couldn't create process");
michael@0 141 PR_Close(readStdin);
michael@0 142 PR_Close(writeStdout);
michael@0 143 PR_Close(writeStderr);
michael@0 144
michael@0 145 mProc = proc;
michael@0 146 mStdinfd = writeStdin;
michael@0 147 mStdoutfd = readStdout;
michael@0 148 mStderrfd = readStderr;
michael@0 149
michael@0 150 free(newArgv[0]);
michael@0 151 free(newArgv[1]);
michael@0 152 PR_DestroyProcessAttr(pattr);
michael@0 153 }
michael@0 154
michael@0 155 void RunToCompletion(uint32_t aWaitMs)
michael@0 156 {
michael@0 157 PR_Close(mStdinfd);
michael@0 158
michael@0 159 PRPollDesc pollfds[2];
michael@0 160 int32_t nfds;
michael@0 161 bool stdoutOpen = true, stderrOpen = true;
michael@0 162 char buf[4096];
michael@0 163 int32_t len;
michael@0 164
michael@0 165 PRIntervalTime now = PR_IntervalNow();
michael@0 166 PRIntervalTime deadline = now + PR_MillisecondsToInterval(aWaitMs);
michael@0 167
michael@0 168 while ((stdoutOpen || stderrOpen) && now < deadline) {
michael@0 169 nfds = 0;
michael@0 170 if (stdoutOpen) {
michael@0 171 pollfds[nfds].fd = mStdoutfd;
michael@0 172 pollfds[nfds].in_flags = PR_POLL_READ;
michael@0 173 pollfds[nfds].out_flags = 0;
michael@0 174 ++nfds;
michael@0 175 }
michael@0 176 if (stderrOpen) {
michael@0 177 pollfds[nfds].fd = mStderrfd;
michael@0 178 pollfds[nfds].in_flags = PR_POLL_READ;
michael@0 179 pollfds[nfds].out_flags = 0;
michael@0 180 ++nfds;
michael@0 181 }
michael@0 182
michael@0 183 int32_t rv = PR_Poll(pollfds, nfds, deadline - now);
michael@0 184 NS_ASSERTION(0 <= rv, PR_ErrorToName(PR_GetError()));
michael@0 185
michael@0 186 if (0 == rv) { // timeout
michael@0 187 fputs("(timed out!)\n", stderr);
michael@0 188 Finish(false); // abnormal
michael@0 189 return;
michael@0 190 }
michael@0 191
michael@0 192 for (int32_t i = 0; i < nfds; ++i) {
michael@0 193 if (!pollfds[i].out_flags)
michael@0 194 continue;
michael@0 195
michael@0 196 bool isStdout = mStdoutfd == pollfds[i].fd;
michael@0 197
michael@0 198 if (PR_POLL_READ & pollfds[i].out_flags) {
michael@0 199 len = PR_Read(pollfds[i].fd, buf, sizeof(buf) - 1);
michael@0 200 NS_ASSERTION(0 <= len, PR_ErrorToName(PR_GetError()));
michael@0 201 }
michael@0 202 else if (PR_POLL_HUP & pollfds[i].out_flags) {
michael@0 203 len = 0;
michael@0 204 }
michael@0 205 else {
michael@0 206 NS_ERROR(PR_ErrorToName(PR_GetError()));
michael@0 207 }
michael@0 208
michael@0 209 if (0 < len) {
michael@0 210 buf[len] = '\0';
michael@0 211 if (isStdout)
michael@0 212 mStdout += buf;
michael@0 213 else
michael@0 214 mStderr += buf;
michael@0 215 }
michael@0 216 else if (isStdout) {
michael@0 217 stdoutOpen = false;
michael@0 218 }
michael@0 219 else {
michael@0 220 stderrOpen = false;
michael@0 221 }
michael@0 222 }
michael@0 223
michael@0 224 now = PR_IntervalNow();
michael@0 225 }
michael@0 226
michael@0 227 if (stdoutOpen)
michael@0 228 fputs("(stdout still open!)\n", stderr);
michael@0 229 if (stderrOpen)
michael@0 230 fputs("(stderr still open!)\n", stderr);
michael@0 231 if (now > deadline)
michael@0 232 fputs("(timed out!)\n", stderr);
michael@0 233
michael@0 234 Finish(!stdoutOpen && !stderrOpen && now <= deadline);
michael@0 235 }
michael@0 236
michael@0 237 private:
michael@0 238 void Finish(bool normalExit) {
michael@0 239 if (!normalExit) {
michael@0 240 PR_KillProcess(mProc);
michael@0 241 mExitCode = -1;
michael@0 242 int32_t dummy;
michael@0 243 PR_WaitProcess(mProc, &dummy);
michael@0 244 }
michael@0 245 else {
michael@0 246 PR_WaitProcess(mProc, &mExitCode); // this had better not block ...
michael@0 247 }
michael@0 248
michael@0 249 PR_Close(mStdoutfd);
michael@0 250 PR_Close(mStderrfd);
michael@0 251 }
michael@0 252
michael@0 253 PRProcess* mProc;
michael@0 254 PRFileDesc* mStdinfd; // writeable
michael@0 255 PRFileDesc* mStdoutfd; // readable
michael@0 256 PRFileDesc* mStderrfd; // readable
michael@0 257 };
michael@0 258
michael@0 259 //-----------------------------------------------------------------------------
michael@0 260 // Harness for checking detector errors
michael@0 261 bool
michael@0 262 CheckForDeadlock(const char* test, const char* const* findTokens)
michael@0 263 {
michael@0 264 Subprocess proc(test);
michael@0 265 proc.RunToCompletion(5000);
michael@0 266
michael@0 267 if (0 == proc.mExitCode)
michael@0 268 return false;
michael@0 269
michael@0 270 int32_t idx = 0;
michael@0 271 for (const char* const* tp = findTokens; *tp; ++tp) {
michael@0 272 const char* const token = *tp;
michael@0 273 #ifdef MOZILLA_INTERNAL_API
michael@0 274 idx = proc.mStderr.Find(token, false, idx);
michael@0 275 #else
michael@0 276 nsCString tokenCString(token);
michael@0 277 idx = proc.mStderr.Find(tokenCString, idx);
michael@0 278 #endif
michael@0 279 if (-1 == idx) {
michael@0 280 printf("(missed token '%s' in output)\n", token);
michael@0 281 puts("----------------------------------\n");
michael@0 282 puts(proc.mStderr.get());
michael@0 283 puts("----------------------------------\n");
michael@0 284 return false;
michael@0 285 }
michael@0 286 idx += strlen(token);
michael@0 287 }
michael@0 288
michael@0 289 return true;
michael@0 290 }
michael@0 291
michael@0 292 //-----------------------------------------------------------------------------
michael@0 293 // Single-threaded sanity tests
michael@0 294
michael@0 295 // Stupidest possible deadlock.
michael@0 296 int
michael@0 297 Sanity_Child()
michael@0 298 {
michael@0 299 TestMutex m1("dd.sanity.m1");
michael@0 300 m1.Lock();
michael@0 301 m1.Lock();
michael@0 302 return 0; // not reached
michael@0 303 }
michael@0 304
michael@0 305 nsresult
michael@0 306 Sanity()
michael@0 307 {
michael@0 308 const char* const tokens[] = {
michael@0 309 "###!!! ERROR: Potential deadlock detected",
michael@0 310 "=== Cyclical dependency starts at\n--- Mutex : dd.sanity.m1",
michael@0 311 "=== Cycle completed at\n--- Mutex : dd.sanity.m1",
michael@0 312 "###!!! Deadlock may happen NOW!", // better catch these easy cases...
michael@0 313 "###!!! ASSERTION: Potential deadlock detected",
michael@0 314 0
michael@0 315 };
michael@0 316 if (CheckForDeadlock("Sanity", tokens)) {
michael@0 317 PASS();
michael@0 318 } else {
michael@0 319 FAIL("deadlock not detected");
michael@0 320 }
michael@0 321 }
michael@0 322
michael@0 323 // Slightly less stupid deadlock.
michael@0 324 int
michael@0 325 Sanity2_Child()
michael@0 326 {
michael@0 327 TestMutex m1("dd.sanity2.m1");
michael@0 328 TestMutex m2("dd.sanity2.m2");
michael@0 329 m1.Lock();
michael@0 330 m2.Lock();
michael@0 331 m1.Lock();
michael@0 332 return 0; // not reached
michael@0 333 }
michael@0 334
michael@0 335 nsresult
michael@0 336 Sanity2()
michael@0 337 {
michael@0 338 const char* const tokens[] = {
michael@0 339 "###!!! ERROR: Potential deadlock detected",
michael@0 340 "=== Cyclical dependency starts at\n--- Mutex : dd.sanity2.m1",
michael@0 341 "--- Next dependency:\n--- Mutex : dd.sanity2.m2",
michael@0 342 "=== Cycle completed at\n--- Mutex : dd.sanity2.m1",
michael@0 343 "###!!! Deadlock may happen NOW!", // better catch these easy cases...
michael@0 344 "###!!! ASSERTION: Potential deadlock detected",
michael@0 345 0
michael@0 346 };
michael@0 347 if (CheckForDeadlock("Sanity2", tokens)) {
michael@0 348 PASS();
michael@0 349 } else {
michael@0 350 FAIL("deadlock not detected");
michael@0 351 }
michael@0 352 }
michael@0 353
michael@0 354
michael@0 355 int
michael@0 356 Sanity3_Child()
michael@0 357 {
michael@0 358 TestMutex m1("dd.sanity3.m1");
michael@0 359 TestMutex m2("dd.sanity3.m2");
michael@0 360 TestMutex m3("dd.sanity3.m3");
michael@0 361 TestMutex m4("dd.sanity3.m4");
michael@0 362
michael@0 363 m1.Lock();
michael@0 364 m2.Lock();
michael@0 365 m3.Lock();
michael@0 366 m4.Lock();
michael@0 367 m4.Unlock();
michael@0 368 m3.Unlock();
michael@0 369 m2.Unlock();
michael@0 370 m1.Unlock();
michael@0 371
michael@0 372 m4.Lock();
michael@0 373 m1.Lock();
michael@0 374 return 0;
michael@0 375 }
michael@0 376
michael@0 377 nsresult
michael@0 378 Sanity3()
michael@0 379 {
michael@0 380 const char* const tokens[] = {
michael@0 381 "###!!! ERROR: Potential deadlock detected",
michael@0 382 "=== Cyclical dependency starts at\n--- Mutex : dd.sanity3.m1",
michael@0 383 "--- Next dependency:\n--- Mutex : dd.sanity3.m2",
michael@0 384 "--- Next dependency:\n--- Mutex : dd.sanity3.m3",
michael@0 385 "--- Next dependency:\n--- Mutex : dd.sanity3.m4",
michael@0 386 "=== Cycle completed at\n--- Mutex : dd.sanity3.m1",
michael@0 387 "###!!! ASSERTION: Potential deadlock detected",
michael@0 388 0
michael@0 389 };
michael@0 390 if (CheckForDeadlock("Sanity3", tokens)) {
michael@0 391 PASS();
michael@0 392 } else {
michael@0 393 FAIL("deadlock not detected");
michael@0 394 }
michael@0 395 }
michael@0 396
michael@0 397
michael@0 398 int
michael@0 399 Sanity4_Child()
michael@0 400 {
michael@0 401 mozilla::ReentrantMonitor m1("dd.sanity4.m1");
michael@0 402 TestMutex m2("dd.sanity4.m2");
michael@0 403 m1.Enter();
michael@0 404 m2.Lock();
michael@0 405 m1.Enter();
michael@0 406 return 0;
michael@0 407 }
michael@0 408
michael@0 409 nsresult
michael@0 410 Sanity4()
michael@0 411 {
michael@0 412 const char* const tokens[] = {
michael@0 413 "Re-entering ReentrantMonitor after acquiring other resources",
michael@0 414 "###!!! ERROR: Potential deadlock detected",
michael@0 415 "=== Cyclical dependency starts at\n--- ReentrantMonitor : dd.sanity4.m1",
michael@0 416 "--- Next dependency:\n--- Mutex : dd.sanity4.m2",
michael@0 417 "=== Cycle completed at\n--- ReentrantMonitor : dd.sanity4.m1",
michael@0 418 "###!!! ASSERTION: Potential deadlock detected",
michael@0 419 0
michael@0 420 };
michael@0 421 if (CheckForDeadlock("Sanity4", tokens)) {
michael@0 422 PASS();
michael@0 423 } else {
michael@0 424 FAIL("deadlock not detected");
michael@0 425 }
michael@0 426 }
michael@0 427
michael@0 428 //-----------------------------------------------------------------------------
michael@0 429 // Multithreaded tests
michael@0 430
michael@0 431 TestMutex* ttM1;
michael@0 432 TestMutex* ttM2;
michael@0 433
michael@0 434 static void
michael@0 435 TwoThreads_thread(void* arg)
michael@0 436 {
michael@0 437 int32_t m1First = NS_PTR_TO_INT32(arg);
michael@0 438 if (m1First) {
michael@0 439 ttM1->Lock();
michael@0 440 ttM2->Lock();
michael@0 441 ttM2->Unlock();
michael@0 442 ttM1->Unlock();
michael@0 443 }
michael@0 444 else {
michael@0 445 ttM2->Lock();
michael@0 446 ttM1->Lock();
michael@0 447 ttM1->Unlock();
michael@0 448 ttM2->Unlock();
michael@0 449 }
michael@0 450 }
michael@0 451
michael@0 452 int
michael@0 453 TwoThreads_Child()
michael@0 454 {
michael@0 455 ttM1 = new TestMutex("dd.twothreads.m1");
michael@0 456 ttM2 = new TestMutex("dd.twothreads.m2");
michael@0 457 if (!ttM1 || !ttM2)
michael@0 458 NS_RUNTIMEABORT("couldn't allocate mutexes");
michael@0 459
michael@0 460 PRThread* t1 = spawn(TwoThreads_thread, (void*) 0);
michael@0 461 PR_JoinThread(t1);
michael@0 462
michael@0 463 PRThread* t2 = spawn(TwoThreads_thread, (void*) 1);
michael@0 464 PR_JoinThread(t2);
michael@0 465
michael@0 466 return 0;
michael@0 467 }
michael@0 468
michael@0 469 nsresult
michael@0 470 TwoThreads()
michael@0 471 {
michael@0 472 const char* const tokens[] = {
michael@0 473 "###!!! ERROR: Potential deadlock detected",
michael@0 474 "=== Cyclical dependency starts at\n--- Mutex : dd.twothreads.m2",
michael@0 475 "--- Next dependency:\n--- Mutex : dd.twothreads.m1",
michael@0 476 "=== Cycle completed at\n--- Mutex : dd.twothreads.m2",
michael@0 477 "###!!! ASSERTION: Potential deadlock detected",
michael@0 478 0
michael@0 479 };
michael@0 480
michael@0 481 if (CheckForDeadlock("TwoThreads", tokens)) {
michael@0 482 PASS();
michael@0 483 } else {
michael@0 484 FAIL("deadlock not detected");
michael@0 485 }
michael@0 486 }
michael@0 487
michael@0 488
michael@0 489 TestMutex* cndMs[4];
michael@0 490 const uint32_t K = 100000;
michael@0 491
michael@0 492 static void
michael@0 493 ContentionNoDeadlock_thread(void* arg)
michael@0 494 {
michael@0 495 int32_t starti = NS_PTR_TO_INT32(arg);
michael@0 496
michael@0 497 for (uint32_t k = 0; k < K; ++k) {
michael@0 498 for (int32_t i = starti; i < (int32_t) ArrayLength(cndMs); ++i)
michael@0 499 cndMs[i]->Lock();
michael@0 500 // comment out the next two lines for deadlocking fun!
michael@0 501 for (int32_t i = ArrayLength(cndMs) - 1; i >= starti; --i)
michael@0 502 cndMs[i]->Unlock();
michael@0 503
michael@0 504 starti = (starti + 1) % 3;
michael@0 505 }
michael@0 506 }
michael@0 507
michael@0 508 int
michael@0 509 ContentionNoDeadlock_Child()
michael@0 510 {
michael@0 511 PRThread* threads[3];
michael@0 512
michael@0 513 for (uint32_t i = 0; i < ArrayLength(cndMs); ++i)
michael@0 514 cndMs[i] = new TestMutex("dd.cnd.ms");
michael@0 515
michael@0 516 for (int32_t i = 0; i < (int32_t) ArrayLength(threads); ++i)
michael@0 517 threads[i] = spawn(ContentionNoDeadlock_thread, NS_INT32_TO_PTR(i));
michael@0 518
michael@0 519 for (uint32_t i = 0; i < ArrayLength(threads); ++i)
michael@0 520 PR_JoinThread(threads[i]);
michael@0 521
michael@0 522 for (uint32_t i = 0; i < ArrayLength(cndMs); ++i)
michael@0 523 delete cndMs[i];
michael@0 524
michael@0 525 return 0;
michael@0 526 }
michael@0 527
michael@0 528 nsresult
michael@0 529 ContentionNoDeadlock()
michael@0 530 {
michael@0 531 const char * func = __func__;
michael@0 532 Subprocess proc(func);
michael@0 533 proc.RunToCompletion(60000);
michael@0 534 if (0 != proc.mExitCode) {
michael@0 535 printf("(expected 0 == return code, got %d)\n", proc.mExitCode);
michael@0 536 puts("(output)\n----------------------------------\n");
michael@0 537 puts(proc.mStdout.get());
michael@0 538 puts("----------------------------------\n");
michael@0 539 puts("(error output)\n----------------------------------\n");
michael@0 540 puts(proc.mStderr.get());
michael@0 541 puts("----------------------------------\n");
michael@0 542
michael@0 543 FAIL("deadlock");
michael@0 544 }
michael@0 545 PASS();
michael@0 546 }
michael@0 547
michael@0 548
michael@0 549
michael@0 550 //-----------------------------------------------------------------------------
michael@0 551
michael@0 552 int
michael@0 553 main(int argc, char** argv)
michael@0 554 {
michael@0 555 if (1 < argc) {
michael@0 556 // XXX can we run w/o scoped XPCOM?
michael@0 557 const char* test = argv[1];
michael@0 558 ScopedXPCOM xpcom(test);
michael@0 559 if (xpcom.failed())
michael@0 560 return 1;
michael@0 561
michael@0 562 // running in a spawned process. call the specificed child function.
michael@0 563 if (!strcmp("Sanity", test))
michael@0 564 return Sanity_Child();
michael@0 565 if (!strcmp("Sanity2", test))
michael@0 566 return Sanity2_Child();
michael@0 567 if (!strcmp("Sanity3", test))
michael@0 568 return Sanity3_Child();
michael@0 569 if (!strcmp("Sanity4", test))
michael@0 570 return Sanity4_Child();
michael@0 571
michael@0 572 if (!strcmp("TwoThreads", test))
michael@0 573 return TwoThreads_Child();
michael@0 574 if (!strcmp("ContentionNoDeadlock", test))
michael@0 575 return ContentionNoDeadlock_Child();
michael@0 576
michael@0 577 fail("%s | %s - unknown child test", __FILE__, __FUNCTION__);
michael@0 578 return 1;
michael@0 579 }
michael@0 580
michael@0 581 ScopedXPCOM xpcom("Storage deadlock detector correctness (" __FILE__ ")");
michael@0 582 if (xpcom.failed())
michael@0 583 return 1;
michael@0 584
michael@0 585 // in the first invocation of this process. we will be the "driver".
michael@0 586 int rv = 0;
michael@0 587
michael@0 588 sPathToThisBinary = argv[0];
michael@0 589
michael@0 590 if (NS_FAILED(Sanity()))
michael@0 591 rv = 1;
michael@0 592 if (NS_FAILED(Sanity2()))
michael@0 593 rv = 1;
michael@0 594 if (NS_FAILED(Sanity3()))
michael@0 595 rv = 1;
michael@0 596 if (NS_FAILED(Sanity4()))
michael@0 597 rv = 1;
michael@0 598
michael@0 599 if (NS_FAILED(TwoThreads()))
michael@0 600 rv = 1;
michael@0 601 if (NS_FAILED(ContentionNoDeadlock()))
michael@0 602 rv = 1;
michael@0 603
michael@0 604 return rv;
michael@0 605 }

mercurial