1 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadMutex 2 // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND 3 // TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND 4 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock 5 // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s 6 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock 7 // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD 8 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRecursiveMutex 9 // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-REC 10 #include <pthread.h> 11 #undef NDEBUG 12 #include <assert.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <unistd.h> 16 #include <new> 17 18 #ifndef LockType 19 #define LockType PthreadMutex 20 #endif 21 22 // You can optionally pass [test_number [iter_count]] on command line. 23 static int test_number = -1; 24 static int iter_count = 100000; 25 26 class PthreadMutex { 27 public: 28 explicit PthreadMutex(bool recursive = false) { 29 if (recursive) { 30 pthread_mutexattr_t attr; 31 pthread_mutexattr_init(&attr); 32 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 33 assert(0 == pthread_mutex_init(&mu_, &attr)); 34 } else { 35 assert(0 == pthread_mutex_init(&mu_, 0)); 36 } 37 } 38 ~PthreadMutex() { 39 assert(0 == pthread_mutex_destroy(&mu_)); 40 (void)padding_; 41 } 42 static bool supports_read_lock() { return false; } 43 static bool supports_recursive_lock() { return false; } 44 void lock() { assert(0 == pthread_mutex_lock(&mu_)); } 45 void unlock() { assert(0 == pthread_mutex_unlock(&mu_)); } 46 bool try_lock() { return 0 == pthread_mutex_trylock(&mu_); } 47 void rdlock() { assert(0); } 48 void rdunlock() { assert(0); } 49 bool try_rdlock() { assert(0); } 50 51 private: 52 pthread_mutex_t mu_; 53 char padding_[64 - sizeof(pthread_mutex_t)]; 54 }; 55 56 class PthreadRecursiveMutex : public PthreadMutex { 57 public: 58 PthreadRecursiveMutex() : PthreadMutex(true) { } 59 static bool supports_recursive_lock() { return true; } 60 }; 61 62 class PthreadSpinLock { 63 public: 64 PthreadSpinLock() { assert(0 == pthread_spin_init(&mu_, 0)); } 65 ~PthreadSpinLock() { 66 assert(0 == pthread_spin_destroy(&mu_)); 67 (void)padding_; 68 } 69 static bool supports_read_lock() { return false; } 70 static bool supports_recursive_lock() { return false; } 71 void lock() { assert(0 == pthread_spin_lock(&mu_)); } 72 void unlock() { assert(0 == pthread_spin_unlock(&mu_)); } 73 bool try_lock() { return 0 == pthread_spin_trylock(&mu_); } 74 void rdlock() { assert(0); } 75 void rdunlock() { assert(0); } 76 bool try_rdlock() { assert(0); } 77 78 private: 79 pthread_spinlock_t mu_; 80 char padding_[64 - sizeof(pthread_spinlock_t)]; 81 }; 82 83 class PthreadRWLock { 84 public: 85 PthreadRWLock() { assert(0 == pthread_rwlock_init(&mu_, 0)); } 86 ~PthreadRWLock() { 87 assert(0 == pthread_rwlock_destroy(&mu_)); 88 (void)padding_; 89 } 90 static bool supports_read_lock() { return true; } 91 static bool supports_recursive_lock() { return false; } 92 void lock() { assert(0 == pthread_rwlock_wrlock(&mu_)); } 93 void unlock() { assert(0 == pthread_rwlock_unlock(&mu_)); } 94 bool try_lock() { return 0 == pthread_rwlock_trywrlock(&mu_); } 95 void rdlock() { assert(0 == pthread_rwlock_rdlock(&mu_)); } 96 void rdunlock() { assert(0 == pthread_rwlock_unlock(&mu_)); } 97 bool try_rdlock() { return 0 == pthread_rwlock_tryrdlock(&mu_); } 98 99 private: 100 pthread_rwlock_t mu_; 101 char padding_[64 - sizeof(pthread_rwlock_t)]; 102 }; 103 104 class LockTest { 105 public: 106 LockTest() : n_(), locks_() {} 107 void Init(size_t n) { 108 n_ = n; 109 locks_ = new LockType*[n_]; 110 for (size_t i = 0; i < n_; i++) 111 locks_[i] = new LockType; 112 } 113 ~LockTest() { 114 for (size_t i = 0; i < n_; i++) 115 delete locks_[i]; 116 delete [] locks_; 117 } 118 void L(size_t i) { 119 assert(i < n_); 120 locks_[i]->lock(); 121 } 122 123 void U(size_t i) { 124 assert(i < n_); 125 locks_[i]->unlock(); 126 } 127 128 void RL(size_t i) { 129 assert(i < n_); 130 locks_[i]->rdlock(); 131 } 132 133 void RU(size_t i) { 134 assert(i < n_); 135 locks_[i]->rdunlock(); 136 } 137 138 void *A(size_t i) { 139 assert(i < n_); 140 return locks_[i]; 141 } 142 143 bool T(size_t i) { 144 assert(i < n_); 145 return locks_[i]->try_lock(); 146 } 147 148 // Simple lock order onversion. 149 void Test1() { 150 if (test_number > 0 && test_number != 1) return; 151 fprintf(stderr, "Starting Test1\n"); 152 // CHECK: Starting Test1 153 Init(5); 154 fprintf(stderr, "Expecting lock inversion: %p %p\n", A(0), A(1)); 155 // CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]] 156 Lock_0_1(); 157 Lock_1_0(); 158 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) 159 // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ([[A1]]) => [[M2:M[0-9]+]] ([[A2]]) => [[M1]] 160 // CHECK: Mutex [[M2]] acquired here while holding mutex [[M1]] 161 // CHECK: #0 pthread_ 162 // CHECK-SECOND: Mutex [[M1]] previously acquired by the same thread here: 163 // CHECK-SECOND: #0 pthread_ 164 // CHECK-NOT-SECOND: second_deadlock_stack=1 to get more informative warning message 165 // CHECK-NOT-SECOND-NOT: #0 pthread_ 166 // CHECK: Mutex [[M1]] acquired here while holding mutex [[M2]] 167 // CHECK: #0 pthread_ 168 // CHECK-SECOND: Mutex [[M2]] previously acquired by the same thread here: 169 // CHECK-SECOND: #0 pthread_ 170 // CHECK-NOT-SECOND-NOT: #0 pthread_ 171 // CHECK-NOT: WARNING: ThreadSanitizer: 172 } 173 174 // Simple lock order inversion with 3 locks. 175 void Test2() { 176 if (test_number > 0 && test_number != 2) return; 177 fprintf(stderr, "Starting Test2\n"); 178 // CHECK: Starting Test2 179 Init(5); 180 fprintf(stderr, "Expecting lock inversion: %p %p %p\n", A(0), A(1), A(2)); 181 // CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]] [[A3:0x[a-f0-9]*]] 182 Lock2(0, 1); 183 Lock2(1, 2); 184 Lock2(2, 0); 185 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) 186 // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ([[A1]]) => [[M2:M[0-9]+]] ([[A2]]) => [[M3:M[0-9]+]] ([[A3]]) => [[M1]] 187 // CHECK-NOT: WARNING: ThreadSanitizer: 188 } 189 190 // Lock order inversion with lots of new locks created (but not used) 191 // between. Since the new locks are not used we should still detect the 192 // deadlock. 193 void Test3() { 194 if (test_number > 0 && test_number != 3) return; 195 fprintf(stderr, "Starting Test3\n"); 196 // CHECK: Starting Test3 197 Init(5); 198 Lock_0_1(); 199 L(2); 200 CreateAndDestroyManyLocks(); 201 U(2); 202 Lock_1_0(); 203 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) 204 // CHECK-NOT: WARNING: ThreadSanitizer: 205 } 206 207 // lock l0=>l1; then create and use lots of locks; then lock l1=>l0. 208 // The deadlock epoch should have changed and we should not report anything. 209 void Test4() { 210 if (test_number > 0 && test_number != 4) return; 211 fprintf(stderr, "Starting Test4\n"); 212 // CHECK: Starting Test4 213 Init(5); 214 Lock_0_1(); 215 L(2); 216 CreateLockUnlockAndDestroyManyLocks(); 217 U(2); 218 Lock_1_0(); 219 // CHECK-NOT: WARNING: ThreadSanitizer: 220 } 221 222 void Test5() { 223 if (test_number > 0 && test_number != 5) return; 224 fprintf(stderr, "Starting Test5\n"); 225 // CHECK: Starting Test5 226 Init(5); 227 RunThreads(&LockTest::Lock_0_1, &LockTest::Lock_1_0); 228 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion 229 // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ({{.*}}) => [[M2:M[0-9]+]] ({{.*}}) => [[M1]] 230 // CHECK: Mutex [[M2]] acquired here while holding mutex [[M1]] in thread [[T1:T[0-9]+]] 231 // CHECK: Mutex [[M1]] acquired here while holding mutex [[M2]] in thread [[T2:T[0-9]+]] 232 // CHECK: Thread [[T1]] {{.*}} created by main thread 233 // CHECK: Thread [[T2]] {{.*}} created by main thread 234 // CHECK-NOT: WARNING: ThreadSanitizer: 235 } 236 237 void Test6() { 238 if (test_number > 0 && test_number != 6) return; 239 fprintf(stderr, "Starting Test6: 3 threads lock/unlock private mutexes\n"); 240 // CHECK: Starting Test6 241 Init(100); 242 // CHECK-NOT: WARNING: ThreadSanitizer: 243 RunThreads(&LockTest::Lock1_Loop_0, &LockTest::Lock1_Loop_1, 244 &LockTest::Lock1_Loop_2); 245 } 246 247 void Test7() { 248 if (test_number > 0 && test_number != 7) return; 249 fprintf(stderr, "Starting Test7\n"); 250 // CHECK: Starting Test7 251 Init(10); 252 L(0); T(1); U(1); U(0); 253 T(1); L(0); U(1); U(0); 254 // CHECK-NOT: WARNING: ThreadSanitizer: 255 fprintf(stderr, "No cycle: 0=>1\n"); 256 // CHECK: No cycle: 0=>1 257 258 T(2); L(3); U(3); U(2); 259 L(3); T(2); U(3); U(2); 260 // CHECK-NOT: WARNING: ThreadSanitizer: 261 fprintf(stderr, "No cycle: 2=>3\n"); 262 // CHECK: No cycle: 2=>3 263 264 T(4); L(5); U(4); U(5); 265 L(5); L(4); U(4); U(5); 266 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion 267 fprintf(stderr, "Have cycle: 4=>5\n"); 268 // CHECK: Have cycle: 4=>5 269 270 L(7); L(6); U(6); U(7); 271 T(6); L(7); U(6); U(7); 272 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion 273 fprintf(stderr, "Have cycle: 6=>7\n"); 274 // CHECK: Have cycle: 6=>7 275 } 276 277 void Test8() { 278 if (test_number > 0 && test_number != 8) return; 279 if (!LockType::supports_read_lock()) return; 280 fprintf(stderr, "Starting Test8\n"); 281 Init(5); 282 // CHECK-RD: Starting Test8 283 RL(0); L(1); RU(0); U(1); 284 L(1); RL(0); RU(0); U(1); 285 // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion 286 fprintf(stderr, "Have cycle: 0=>1\n"); 287 // CHECK-RD: Have cycle: 0=>1 288 289 RL(2); RL(3); RU(2); RU(3); 290 RL(3); RL(2); RU(2); RU(3); 291 // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion 292 fprintf(stderr, "Have cycle: 2=>3\n"); 293 // CHECK-RD: Have cycle: 2=>3 294 } 295 296 void Test9() { 297 if (test_number > 0 && test_number != 9) return; 298 if (!LockType::supports_recursive_lock()) return; 299 fprintf(stderr, "Starting Test9\n"); 300 // CHECK-REC: Starting Test9 301 Init(5); 302 L(0); L(0); L(0); L(1); U(1); U(0); U(0); U(0); 303 L(1); L(1); L(1); L(0); U(0); U(1); U(1); U(1); 304 // CHECK-REC: WARNING: ThreadSanitizer: lock-order-inversion 305 } 306 307 void Test10() { 308 if (test_number > 0 && test_number != 10) return; 309 fprintf(stderr, "Starting Test10: 4 threads lock/unlock 4 private mutexes, one under another\n"); 310 // CHECK: Starting Test10 311 Init(100); 312 // CHECK-NOT: WARNING: ThreadSanitizer: 313 RunThreads(&LockTest::Test10_Thread1, &LockTest::Test10_Thread2, 314 &LockTest::Test10_Thread3, &LockTest::Test10_Thread4); 315 } 316 void Test10_Thread1() { Test10_Thread(0); } 317 void Test10_Thread2() { Test10_Thread(10); } 318 void Test10_Thread3() { Test10_Thread(20); } 319 void Test10_Thread4() { Test10_Thread(30); } 320 void Test10_Thread(size_t m) { 321 for (int i = 0; i < iter_count; i++) { 322 L(m + 0); 323 L(m + 1); 324 L(m + 2); 325 L(m + 3); 326 U(m + 3); 327 U(m + 2); 328 U(m + 1); 329 U(m + 0); 330 } 331 } 332 333 void Test11() { 334 if (test_number > 0 && test_number != 11) return; 335 fprintf(stderr, "Starting Test11: 4 threads lock/unlock 4 private mutexes, all under another private mutex\n"); 336 // CHECK: Starting Test11 337 Init(500); 338 // CHECK-NOT: WARNING: ThreadSanitizer: 339 RunThreads(&LockTest::Test11_Thread1, &LockTest::Test11_Thread2, 340 &LockTest::Test11_Thread3, &LockTest::Test11_Thread4); 341 } 342 void Test11_Thread1() { Test10_Thread(0); } 343 void Test11_Thread2() { Test10_Thread(10); } 344 void Test11_Thread3() { Test10_Thread(20); } 345 void Test11_Thread4() { Test10_Thread(30); } 346 void Test11_Thread(size_t m) { 347 for (int i = 0; i < iter_count; i++) { 348 L(m); 349 L(m + 100); 350 U(m + 100); 351 L(m + 200); 352 U(m + 200); 353 L(m + 300); 354 U(m + 300); 355 L(m + 400); 356 U(m + 500); 357 U(m); 358 } 359 } 360 361 void Test12() { 362 if (test_number > 0 && test_number != 12) return; 363 if (!LockType::supports_read_lock()) return; 364 fprintf(stderr, "Starting Test12: 4 threads read lock/unlock 4 shared mutexes, one under another\n"); 365 // CHECK-RD: Starting Test12 366 Init(500); 367 // CHECK-RD-NOT: WARNING: ThreadSanitizer: 368 RunThreads(&LockTest::Test12_Thread, &LockTest::Test12_Thread, 369 &LockTest::Test12_Thread, &LockTest::Test12_Thread); 370 } 371 void Test12_Thread() { 372 for (int i = 0; i < iter_count; i++) { 373 RL(000); 374 RL(100); 375 RL(200); 376 RL(300); 377 RU(300); 378 RU(200); 379 RU(100); 380 RU(000); 381 } 382 } 383 384 void Test13() { 385 if (test_number > 0 && test_number != 13) return; 386 if (!LockType::supports_read_lock()) return; 387 fprintf(stderr, "Starting Test13: 4 threads read lock/unlock 4 shared mutexes, all under another shared mutex\n"); 388 // CHECK-RD: Starting Test13 389 Init(500); 390 // CHECK-RD-NOT: WARNING: ThreadSanitizer: 391 RunThreads(&LockTest::Test13_Thread, &LockTest::Test13_Thread, 392 &LockTest::Test13_Thread, &LockTest::Test13_Thread); 393 } 394 void Test13_Thread() { 395 for (int i = 0; i < iter_count; i++) { 396 RL(0); 397 RL(100); 398 RU(100); 399 RL(200); 400 RU(200); 401 RL(300); 402 RU(300); 403 RL(400); 404 RU(400); 405 RU(0); 406 } 407 } 408 409 void Test14() { 410 if (test_number > 0 && test_number != 14) return; 411 fprintf(stderr, "Starting Test14: create lots of locks in 4 threads\n"); 412 Init(10); 413 // CHECK-RD: Starting Test14 414 RunThreads(&LockTest::CreateAndDestroyLocksLoop, 415 &LockTest::CreateAndDestroyLocksLoop, 416 &LockTest::CreateAndDestroyLocksLoop, 417 &LockTest::CreateAndDestroyLocksLoop); 418 } 419 420 void Test15() { 421 if (test_number > 0 && test_number != 15) return; 422 if (!LockType::supports_read_lock()) return; 423 fprintf(stderr, "Starting Test15: recursive rlock\n"); 424 // DISABLEDCHECK-RD: Starting Test15 425 Init(5); 426 RL(0); RL(0); RU(0); RU(0); // Recusrive reader lock. 427 RL(0); RL(0); RL(0); RU(0); RU(0); RU(0); // Recusrive reader lock. 428 } 429 430 // More detailed output test. 431 void Test16() { 432 if (test_number > 0 && test_number != 16) return; 433 fprintf(stderr, "Starting Test16: detailed output test with two locks\n"); 434 // CHECK: Starting Test16 435 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion 436 // CHECK: acquired here while holding mutex 437 // CHECK: LockTest::Acquire1 438 // CHECK-NEXT: LockTest::Acquire_0_then_1 439 // CHECK-SECOND: previously acquired by the same thread here 440 // CHECK-SECOND: LockTest::Acquire0 441 // CHECK-SECOND-NEXT: LockTest::Acquire_0_then_1 442 // CHECK: acquired here while holding mutex 443 // CHECK: LockTest::Acquire0 444 // CHECK-NEXT: LockTest::Acquire_1_then_0 445 // CHECK-SECOND: previously acquired by the same thread here 446 // CHECK-SECOND: LockTest::Acquire1 447 // CHECK-SECOND-NEXT: LockTest::Acquire_1_then_0 448 Init(5); 449 Acquire_0_then_1(); 450 U(0); U(1); 451 Acquire_1_then_0(); 452 U(0); U(1); 453 } 454 455 // More detailed output test. 456 void Test17() { 457 if (test_number > 0 && test_number != 17) return; 458 fprintf(stderr, "Starting Test17: detailed output test with three locks\n"); 459 // CHECK: Starting Test17 460 // CHECK: WARNING: ThreadSanitizer: lock-order-inversion 461 // CHECK: LockTest::Acquire1 462 // CHECK-NEXT: LockTest::Acquire_0_then_1 463 // CHECK: LockTest::Acquire2 464 // CHECK-NEXT: LockTest::Acquire_1_then_2 465 // CHECK: LockTest::Acquire0 466 // CHECK-NEXT: LockTest::Acquire_2_then_0 467 Init(5); 468 Acquire_0_then_1(); 469 U(0); U(1); 470 Acquire_1_then_2(); 471 U(1); U(2); 472 Acquire_2_then_0(); 473 U(0); U(2); 474 } 475 476 __attribute__((noinline)) void Acquire2() { L(2); } 477 __attribute__((noinline)) void Acquire1() { L(1); } 478 __attribute__((noinline)) void Acquire0() { L(0); } 479 __attribute__((noinline)) void Acquire_1_then_0() { Acquire1(); Acquire0(); } 480 __attribute__((noinline)) void Acquire_0_then_1() { Acquire0(); Acquire1(); } 481 __attribute__((noinline)) void Acquire_1_then_2() { Acquire1(); Acquire2(); } 482 __attribute__((noinline)) void Acquire_2_then_0() { Acquire2(); Acquire0(); } 483 484 // This test creates, locks, unlocks and destroys lots of mutexes. 485 void Test18() { 486 if (test_number > 0 && test_number != 18) return; 487 fprintf(stderr, "Starting Test18: create, lock and destroy 4 locks; all in " 488 "4 threads in a loop\n"); 489 RunThreads(&LockTest::Test18_Thread, &LockTest::Test18_Thread, 490 &LockTest::Test18_Thread, &LockTest::Test18_Thread); 491 } 492 493 void Test18_Thread() { 494 LockType *l = new LockType[4]; 495 for (size_t i = 0; i < iter_count / 100; i++) { 496 for (int i = 0; i < 4; i++) l[i].lock(); 497 for (int i = 0; i < 4; i++) l[i].unlock(); 498 for (int i = 0; i < 4; i++) l[i].~LockType(); 499 for (int i = 0; i < 4; i++) new ((void*)&l[i]) LockType(); 500 } 501 delete [] l; 502 } 503 504 private: 505 void Lock2(size_t l1, size_t l2) { L(l1); L(l2); U(l2); U(l1); } 506 void Lock_0_1() { Lock2(0, 1); } 507 void Lock_1_0() { sleep(1); Lock2(1, 0); } 508 void Lock1_Loop(size_t i, size_t n_iter) { 509 for (size_t it = 0; it < n_iter; it++) { 510 // if ((it & (it - 1)) == 0) fprintf(stderr, "%zd", i); 511 L(i); 512 U(i); 513 } 514 // fprintf(stderr, "\n"); 515 } 516 void Lock1_Loop_0() { Lock1_Loop(0, iter_count); } 517 void Lock1_Loop_1() { Lock1_Loop(10, iter_count); } 518 void Lock1_Loop_2() { Lock1_Loop(20, iter_count); } 519 520 void CreateAndDestroyManyLocks() { 521 LockType *create_many_locks_but_never_acquire = 522 new LockType[kDeadlockGraphSize]; 523 (void)create_many_locks_but_never_acquire; 524 delete [] create_many_locks_but_never_acquire; 525 } 526 527 void CreateAndDestroyLocksLoop() { 528 for (size_t it = 0; it <= iter_count; it++) { 529 LockType some_locks[10]; 530 (void)some_locks; 531 } 532 } 533 534 void CreateLockUnlockAndDestroyManyLocks() { 535 LockType many_locks[kDeadlockGraphSize]; 536 for (size_t i = 0; i < kDeadlockGraphSize; i++) { 537 many_locks[i].lock(); 538 many_locks[i].unlock(); 539 } 540 } 541 542 // LockTest Member function callback. 543 struct CB { 544 void (LockTest::*f)(); 545 LockTest *lt; 546 }; 547 548 // Thread function with CB. 549 static void *Thread(void *param) { 550 CB *cb = (CB*)param; 551 (cb->lt->*cb->f)(); 552 return NULL; 553 } 554 555 void RunThreads(void (LockTest::*f1)(), void (LockTest::*f2)(), 556 void (LockTest::*f3)() = 0, void (LockTest::*f4)() = 0) { 557 const int kNumThreads = 4; 558 pthread_t t[kNumThreads]; 559 CB cb[kNumThreads] = {{f1, this}, {f2, this}, {f3, this}, {f4, this}}; 560 for (int i = 0; i < kNumThreads && cb[i].f; i++) 561 pthread_create(&t[i], 0, Thread, &cb[i]); 562 for (int i = 0; i < kNumThreads && cb[i].f; i++) 563 pthread_join(t[i], 0); 564 } 565 566 static const size_t kDeadlockGraphSize = 4096; 567 size_t n_; 568 LockType **locks_; 569 }; 570 571 int main(int argc, char **argv) { 572 if (argc > 1) 573 test_number = atoi(argv[1]); 574 if (argc > 2) 575 iter_count = atoi(argv[2]); 576 LockTest().Test1(); 577 LockTest().Test2(); 578 LockTest().Test3(); 579 LockTest().Test4(); 580 LockTest().Test5(); 581 LockTest().Test6(); 582 LockTest().Test7(); 583 LockTest().Test8(); 584 LockTest().Test9(); 585 LockTest().Test10(); 586 LockTest().Test11(); 587 LockTest().Test12(); 588 LockTest().Test13(); 589 LockTest().Test14(); 590 LockTest().Test15(); 591 LockTest().Test16(); 592 LockTest().Test17(); 593 LockTest().Test18(); 594 fprintf(stderr, "ALL-DONE\n"); 595 // CHECK: ALL-DONE 596 } 597