1 //===-- tsan_mutex.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_atomic.h"
13 #include "tsan_interface.h"
14 #include "tsan_interface_ann.h"
15 #include "tsan_test_util.h"
16 #include "gtest/gtest.h"
17 #include <stdint.h>
18 
19 namespace __tsan {
20 
TEST(ThreadSanitizer,BasicMutex)21 TEST(ThreadSanitizer, BasicMutex) {
22   ScopedThread t;
23   Mutex m;
24   t.Create(m);
25 
26   t.Lock(m);
27   t.Unlock(m);
28 
29   CHECK(t.TryLock(m));
30   t.Unlock(m);
31 
32   t.Lock(m);
33   CHECK(!t.TryLock(m));
34   t.Unlock(m);
35 
36   t.Destroy(m);
37 }
38 
TEST(ThreadSanitizer,BasicSpinMutex)39 TEST(ThreadSanitizer, BasicSpinMutex) {
40   ScopedThread t;
41   Mutex m(Mutex::Spin);
42   t.Create(m);
43 
44   t.Lock(m);
45   t.Unlock(m);
46 
47   CHECK(t.TryLock(m));
48   t.Unlock(m);
49 
50   t.Lock(m);
51   CHECK(!t.TryLock(m));
52   t.Unlock(m);
53 
54   t.Destroy(m);
55 }
56 
TEST(ThreadSanitizer,BasicRwMutex)57 TEST(ThreadSanitizer, BasicRwMutex) {
58   ScopedThread t;
59   Mutex m(Mutex::RW);
60   t.Create(m);
61 
62   t.Lock(m);
63   t.Unlock(m);
64 
65   CHECK(t.TryLock(m));
66   t.Unlock(m);
67 
68   t.Lock(m);
69   CHECK(!t.TryLock(m));
70   t.Unlock(m);
71 
72   t.ReadLock(m);
73   t.ReadUnlock(m);
74 
75   CHECK(t.TryReadLock(m));
76   t.ReadUnlock(m);
77 
78   t.Lock(m);
79   CHECK(!t.TryReadLock(m));
80   t.Unlock(m);
81 
82   t.ReadLock(m);
83   CHECK(!t.TryLock(m));
84   t.ReadUnlock(m);
85 
86   t.ReadLock(m);
87   CHECK(t.TryReadLock(m));
88   t.ReadUnlock(m);
89   t.ReadUnlock(m);
90 
91   t.Destroy(m);
92 }
93 
TEST(ThreadSanitizer,Mutex)94 TEST(ThreadSanitizer, Mutex) {
95   Mutex m;
96   MainThread t0;
97   t0.Create(m);
98 
99   ScopedThread t1, t2;
100   MemLoc l;
101   t1.Lock(m);
102   t1.Write1(l);
103   t1.Unlock(m);
104   t2.Lock(m);
105   t2.Write1(l);
106   t2.Unlock(m);
107   t2.Destroy(m);
108 }
109 
TEST(ThreadSanitizer,SpinMutex)110 TEST(ThreadSanitizer, SpinMutex) {
111   Mutex m(Mutex::Spin);
112   MainThread t0;
113   t0.Create(m);
114 
115   ScopedThread t1, t2;
116   MemLoc l;
117   t1.Lock(m);
118   t1.Write1(l);
119   t1.Unlock(m);
120   t2.Lock(m);
121   t2.Write1(l);
122   t2.Unlock(m);
123   t2.Destroy(m);
124 }
125 
TEST(ThreadSanitizer,RwMutex)126 TEST(ThreadSanitizer, RwMutex) {
127   Mutex m(Mutex::RW);
128   MainThread t0;
129   t0.Create(m);
130 
131   ScopedThread t1, t2, t3;
132   MemLoc l;
133   t1.Lock(m);
134   t1.Write1(l);
135   t1.Unlock(m);
136   t2.Lock(m);
137   t2.Write1(l);
138   t2.Unlock(m);
139   t1.ReadLock(m);
140   t3.ReadLock(m);
141   t1.Read1(l);
142   t3.Read1(l);
143   t1.ReadUnlock(m);
144   t3.ReadUnlock(m);
145   t2.Lock(m);
146   t2.Write1(l);
147   t2.Unlock(m);
148   t2.Destroy(m);
149 }
150 
TEST(ThreadSanitizer,StaticMutex)151 TEST(ThreadSanitizer, StaticMutex) {
152   // Emulates statically initialized mutex.
153   Mutex m;
154   m.StaticInit();
155   {
156     ScopedThread t1, t2;
157     t1.Lock(m);
158     t1.Unlock(m);
159     t2.Lock(m);
160     t2.Unlock(m);
161   }
162   MainThread().Destroy(m);
163 }
164 
singleton_thread(void * param)165 static void *singleton_thread(void *param) {
166   atomic_uintptr_t *singleton = (atomic_uintptr_t *)param;
167   for (int i = 0; i < 4*1024*1024; i++) {
168     int *val = (int *)atomic_load(singleton, memory_order_acquire);
169     __tsan_acquire(singleton);
170     __tsan_read4(val);
171     CHECK_EQ(*val, 42);
172   }
173   return 0;
174 }
175 
TEST(DISABLED_BENCH_ThreadSanitizer,Singleton)176 TEST(DISABLED_BENCH_ThreadSanitizer, Singleton) {
177   const int kClockSize = 100;
178   const int kThreadCount = 8;
179 
180   // Puff off thread's clock.
181   for (int i = 0; i < kClockSize; i++) {
182     ScopedThread t1;
183     (void)t1;
184   }
185   // Create the singleton.
186   int val = 42;
187   __tsan_write4(&val);
188   atomic_uintptr_t singleton;
189   __tsan_release(&singleton);
190   atomic_store(&singleton, (uintptr_t)&val, memory_order_release);
191   // Create reader threads.
192   pthread_t threads[kThreadCount];
193   for (int t = 0; t < kThreadCount; t++)
194     pthread_create(&threads[t], 0, singleton_thread, &singleton);
195   for (int t = 0; t < kThreadCount; t++)
196     pthread_join(threads[t], 0);
197 }
198 
TEST(DISABLED_BENCH_ThreadSanitizer,StopFlag)199 TEST(DISABLED_BENCH_ThreadSanitizer, StopFlag) {
200   const int kClockSize = 100;
201   const int kIters = 16*1024*1024;
202 
203   // Puff off thread's clock.
204   for (int i = 0; i < kClockSize; i++) {
205     ScopedThread t1;
206     (void)t1;
207   }
208   // Create the stop flag.
209   atomic_uintptr_t flag;
210   __tsan_release(&flag);
211   atomic_store(&flag, 0, memory_order_release);
212   // Read it a lot.
213   for (int i = 0; i < kIters; i++) {
214     uptr v = atomic_load(&flag, memory_order_acquire);
215     __tsan_acquire(&flag);
216     CHECK_EQ(v, 0);
217   }
218 }
219 
220 }  // namespace __tsan
221