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 21 TEST(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 39 TEST(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 57 TEST(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 94 TEST(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(l); 103 t1.Unlock(m); 104 t2.Lock(m); 105 t2.Write1(l); 106 t2.Unlock(m); 107 t2.Destroy(m); 108 } 109 110 TEST(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(l); 119 t1.Unlock(m); 120 t2.Lock(m); 121 t2.Write1(l); 122 t2.Unlock(m); 123 t2.Destroy(m); 124 } 125 126 TEST(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(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 151 TEST(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 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 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 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