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