forked from OSchip/llvm-project
221 lines
4.3 KiB
C++
221 lines
4.3 KiB
C++
//===-- tsan_mutex.cpp ----------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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;
|
|
UserMutex 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;
|
|
UserMutex m(UserMutex::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;
|
|
UserMutex m(UserMutex::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) {
|
|
UserMutex 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) {
|
|
UserMutex m(UserMutex::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) {
|
|
UserMutex m(UserMutex::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.
|
|
UserMutex 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
|