You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
4.2 KiB
222 lines
4.2 KiB
//===-- 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 <stdint.h>
|
|
|
|
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
|