llvm-project/compiler-rt/lib/tsan/rtl_tests/tsan_test_util.h

123 lines
3.5 KiB
C++

//===-- tsan_test_util.h ----------------------------------------*- C++ -*-===//
//
// 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.
//
// Test utils.
//===----------------------------------------------------------------------===//
#ifndef TSAN_TEST_UTIL_H
#define TSAN_TEST_UTIL_H
void TestMutexBeforeInit();
// A location of memory on which a race may be detected.
class MemLoc {
public:
explicit MemLoc(int offset_from_aligned = 0);
explicit MemLoc(void *const real_addr) : loc_(real_addr) { }
~MemLoc();
void *loc() const { return loc_; }
private:
void *const loc_;
MemLoc(const MemLoc&);
void operator = (const MemLoc&);
};
class Mutex {
public:
enum Type { Normal, Spin, RW };
explicit Mutex(Type type = Normal);
~Mutex();
void Init();
void StaticInit(); // Emulates static initalization (tsan invisible).
void Destroy();
void Lock();
bool TryLock();
void Unlock();
void ReadLock();
bool TryReadLock();
void ReadUnlock();
private:
// Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever.
void *mtx_[128];
bool alive_;
const Type type_;
Mutex(const Mutex&);
void operator = (const Mutex&);
};
// A thread is started in CTOR and joined in DTOR.
class ScopedThread {
public:
explicit ScopedThread(bool detached = false, bool main = false);
~ScopedThread();
void Detach();
void Access(void *addr, bool is_write, int size, bool expect_race);
void Read(const MemLoc &ml, int size, bool expect_race = false) {
Access(ml.loc(), false, size, expect_race);
}
void Write(const MemLoc &ml, int size, bool expect_race = false) {
Access(ml.loc(), true, size, expect_race);
}
void Read1(const MemLoc &ml, bool expect_race = false) {
Read(ml, 1, expect_race); }
void Read2(const MemLoc &ml, bool expect_race = false) {
Read(ml, 2, expect_race); }
void Read4(const MemLoc &ml, bool expect_race = false) {
Read(ml, 4, expect_race); }
void Read8(const MemLoc &ml, bool expect_race = false) {
Read(ml, 8, expect_race); }
void Write1(const MemLoc &ml, bool expect_race = false) {
Write(ml, 1, expect_race); }
void Write2(const MemLoc &ml, bool expect_race = false) {
Write(ml, 2, expect_race); }
void Write4(const MemLoc &ml, bool expect_race = false) {
Write(ml, 4, expect_race); }
void Write8(const MemLoc &ml, bool expect_race = false) {
Write(ml, 8, expect_race); }
void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val,
bool expect_race = false);
void Call(void(*pc)());
void Return();
void Create(const Mutex &m);
void Destroy(const Mutex &m);
void Lock(const Mutex &m);
bool TryLock(const Mutex &m);
void Unlock(const Mutex &m);
void ReadLock(const Mutex &m);
bool TryReadLock(const Mutex &m);
void ReadUnlock(const Mutex &m);
void Memcpy(void *dst, const void *src, int size, bool expect_race = false);
void Memset(void *dst, int val, int size, bool expect_race = false);
private:
struct Impl;
Impl *impl_;
ScopedThread(const ScopedThread&); // Not implemented.
void operator = (const ScopedThread&); // Not implemented.
};
class MainThread : public ScopedThread {
public:
MainThread()
: ScopedThread(false, true) {
}
};
#endif // #ifndef TSAN_TEST_UTIL_H