1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//===-- 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
|