//===-- tsan_mutex.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" #include "tsan_interface.h" #include "tsan_interface_ann.h" #include "tsan_test_util.h" #include "gtest/gtest.h" #include namespace __tsan { TEST(ThreadSanitizer, BasicMutex) { ScopedThread t; Mutex m; t.Create(m); t.Lock(m); t.Unlock(m); CHECK(t.TryLock(m)); t.Unlock(m); t.Lock(m); CHECK(!t.TryLock(m)); t.Unlock(m); t.Destroy(m); } TEST(ThreadSanitizer, BasicSpinMutex) { ScopedThread t; Mutex m(Mutex::Spin); t.Create(m); t.Lock(m); t.Unlock(m); CHECK(t.TryLock(m)); t.Unlock(m); t.Lock(m); CHECK(!t.TryLock(m)); t.Unlock(m); t.Destroy(m); } TEST(ThreadSanitizer, BasicRwMutex) { ScopedThread t; Mutex m(Mutex::RW); t.Create(m); t.Lock(m); t.Unlock(m); CHECK(t.TryLock(m)); t.Unlock(m); t.Lock(m); CHECK(!t.TryLock(m)); t.Unlock(m); t.ReadLock(m); t.ReadUnlock(m); CHECK(t.TryReadLock(m)); t.ReadUnlock(m); t.Lock(m); CHECK(!t.TryReadLock(m)); t.Unlock(m); t.ReadLock(m); CHECK(!t.TryLock(m)); t.ReadUnlock(m); t.ReadLock(m); CHECK(t.TryReadLock(m)); t.ReadUnlock(m); t.ReadUnlock(m); t.Destroy(m); } TEST(ThreadSanitizer, Mutex) { Mutex m; MainThread t0; t0.Create(m); ScopedThread t1, t2; MemLoc l; t1.Lock(m); t1.Write1(l); t1.Unlock(m); t2.Lock(m); t2.Write1(l); t2.Unlock(m); t2.Destroy(m); } TEST(ThreadSanitizer, SpinMutex) { Mutex m(Mutex::Spin); MainThread t0; t0.Create(m); ScopedThread t1, t2; MemLoc l; t1.Lock(m); t1.Write1(l); t1.Unlock(m); t2.Lock(m); t2.Write1(l); t2.Unlock(m); t2.Destroy(m); } TEST(ThreadSanitizer, RwMutex) { Mutex m(Mutex::RW); MainThread t0; t0.Create(m); ScopedThread t1, t2, t3; MemLoc l; t1.Lock(m); t1.Write1(l); t1.Unlock(m); t2.Lock(m); t2.Write1(l); t2.Unlock(m); t1.ReadLock(m); t3.ReadLock(m); t1.Read1(l); t3.Read1(l); t1.ReadUnlock(m); t3.ReadUnlock(m); t2.Lock(m); t2.Write1(l); t2.Unlock(m); t2.Destroy(m); } TEST(ThreadSanitizer, StaticMutex) { // Emulates statically initialized mutex. Mutex m; m.StaticInit(); { ScopedThread t1, t2; t1.Lock(m); t1.Unlock(m); t2.Lock(m); t2.Unlock(m); } MainThread().Destroy(m); } static void *singleton_thread(void *param) { atomic_uintptr_t *singleton = (atomic_uintptr_t *)param; for (int i = 0; i < 4*1024*1024; i++) { int *val = (int *)atomic_load(singleton, memory_order_acquire); __tsan_acquire(singleton); __tsan_read4(val); CHECK_EQ(*val, 42); } return 0; } TEST(DISABLED_BENCH_ThreadSanitizer, Singleton) { const int kClockSize = 100; const int kThreadCount = 8; // Puff off thread's clock. for (int i = 0; i < kClockSize; i++) { ScopedThread t1; (void)t1; } // Create the singleton. int val = 42; __tsan_write4(&val); atomic_uintptr_t singleton; __tsan_release(&singleton); atomic_store(&singleton, (uintptr_t)&val, memory_order_release); // Create reader threads. pthread_t threads[kThreadCount]; for (int t = 0; t < kThreadCount; t++) pthread_create(&threads[t], 0, singleton_thread, &singleton); for (int t = 0; t < kThreadCount; t++) pthread_join(threads[t], 0); } TEST(DISABLED_BENCH_ThreadSanitizer, StopFlag) { const int kClockSize = 100; const int kIters = 16*1024*1024; // Puff off thread's clock. for (int i = 0; i < kClockSize; i++) { ScopedThread t1; (void)t1; } // Create the stop flag. atomic_uintptr_t flag; __tsan_release(&flag); atomic_store(&flag, 0, memory_order_release); // Read it a lot. for (int i = 0; i < kIters; i++) { uptr v = atomic_load(&flag, memory_order_acquire); __tsan_acquire(&flag); CHECK_EQ(v, 0); } } } // namespace __tsan