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
19namespace __tsan {
20
21TEST_F(ThreadSanitizer, BasicMutex) {
22 ScopedThread t;
23 UserMutex 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
39TEST_F(ThreadSanitizer, BasicSpinMutex) {
40 ScopedThread t;
41 UserMutex m(UserMutex::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
57TEST_F(ThreadSanitizer, BasicRwMutex) {
58 ScopedThread t;
59 UserMutex m(UserMutex::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
94TEST_F(ThreadSanitizer, Mutex) {
95 UserMutex m;
96 MainThread t0;
97 t0.Create(m);
98
99 ScopedThread t1, t2;
100 MemLoc l;
101 t1.Lock(m);
102 t1.Write1(ml: l);
103 t1.Unlock(m);
104 t2.Lock(m);
105 t2.Write1(ml: l);
106 t2.Unlock(m);
107 t2.Destroy(m);
108}
109
110TEST_F(ThreadSanitizer, SpinMutex) {
111 UserMutex m(UserMutex::Spin);
112 MainThread t0;
113 t0.Create(m);
114
115 ScopedThread t1, t2;
116 MemLoc l;
117 t1.Lock(m);
118 t1.Write1(ml: l);
119 t1.Unlock(m);
120 t2.Lock(m);
121 t2.Write1(ml: l);
122 t2.Unlock(m);
123 t2.Destroy(m);
124}
125
126TEST_F(ThreadSanitizer, RwMutex) {
127 UserMutex m(UserMutex::RW);
128 MainThread t0;
129 t0.Create(m);
130
131 ScopedThread t1, t2, t3;
132 MemLoc l;
133 t1.Lock(m);
134 t1.Write1(ml: l);
135 t1.Unlock(m);
136 t2.Lock(m);
137 t2.Write1(ml: l);
138 t2.Unlock(m);
139 t1.ReadLock(m);
140 t3.ReadLock(m);
141 t1.Read1(ml: l);
142 t3.Read1(ml: l);
143 t1.ReadUnlock(m);
144 t3.ReadUnlock(m);
145 t2.Lock(m);
146 t2.Write1(ml: l);
147 t2.Unlock(m);
148 t2.Destroy(m);
149}
150
151TEST_F(ThreadSanitizer, StaticMutex) {
152 // Emulates statically initialized mutex.
153 UserMutex 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
165static 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(a: singleton, mo: memory_order_acquire);
169 __tsan_acquire(addr: singleton);
170 __tsan_read4(addr: val);
171 CHECK_EQ(*val, 42);
172 }
173 return 0;
174}
175
176TEST(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(addr: &val);
188 atomic_uintptr_t singleton;
189 __tsan_release(addr: &singleton);
190 atomic_store(a: &singleton, v: (uintptr_t)&val, mo: 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
199TEST(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(addr: &flag);
211 atomic_store(a: &flag, v: 0, mo: memory_order_release);
212 // Read it a lot.
213 for (int i = 0; i < kIters; i++) {
214 uptr v = atomic_load(a: &flag, mo: memory_order_acquire);
215 __tsan_acquire(addr: &flag);
216 CHECK_EQ(v, 0);
217 }
218}
219
220} // namespace __tsan
221

source code of compiler-rt/lib/tsan/tests/rtl/tsan_mutex.cpp