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