221 lines · cpp
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-exception6//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(l);103 t1.Unlock(m);104 t2.Lock(m);105 t2.Write1(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(l);119 t1.Unlock(m);120 t2.Lock(m);121 t2.Write1(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(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 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(singleton, memory_order_acquire);169 __tsan_acquire(singleton);170 __tsan_read4(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(&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 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(&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 __tsan221