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