137 lines
3.7 KiB
C++
137 lines
3.7 KiB
C++
//===-- tsan_test_util.h ----------------------------------------*- C++ -*-===//
|
|
//
|
|
// 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.
|
|
//
|
|
// Test utils.
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef TSAN_TEST_UTIL_H
|
|
#define TSAN_TEST_UTIL_H
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
class ThreadSanitizer : public ::testing::Test {
|
|
protected:
|
|
void TearDown() override;
|
|
};
|
|
|
|
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 UserMutex {
|
|
public:
|
|
enum Type {
|
|
Normal,
|
|
RW,
|
|
#ifndef __APPLE__
|
|
Spin
|
|
#else
|
|
Spin = Normal
|
|
#endif
|
|
};
|
|
|
|
explicit UserMutex(Type type = Normal);
|
|
~UserMutex();
|
|
|
|
void Init();
|
|
void StaticInit(); // Emulates static initialization (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_;
|
|
|
|
UserMutex(const UserMutex &);
|
|
void operator=(const UserMutex &);
|
|
};
|
|
|
|
// 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 UserMutex &m);
|
|
void Destroy(const UserMutex &m);
|
|
void Lock(const UserMutex &m);
|
|
bool TryLock(const UserMutex &m);
|
|
void Unlock(const UserMutex &m);
|
|
void ReadLock(const UserMutex &m);
|
|
bool TryReadLock(const UserMutex &m);
|
|
void ReadUnlock(const UserMutex &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
|