1//===-- tsan_test_util.h ----------------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file is a part of ThreadSanitizer (TSan), a race detector. 10// 11// Test utils. 12//===----------------------------------------------------------------------===// 13#ifndef TSAN_TEST_UTIL_H 14#define TSAN_TEST_UTIL_H 15 16#include "gtest/gtest.h" 17 18class ThreadSanitizer : public ::testing::Test { 19 protected: 20 void TearDown() override; 21}; 22 23void TestMutexBeforeInit(); 24 25// A location of memory on which a race may be detected. 26class MemLoc { 27 public: 28 explicit MemLoc(int offset_from_aligned = 0); 29 explicit MemLoc(void *const real_addr) : loc_(real_addr) { } 30 ~MemLoc(); 31 void *loc() const { return loc_; } 32 private: 33 void *const loc_; 34 MemLoc(const MemLoc&); 35 void operator = (const MemLoc&); 36}; 37 38class UserMutex { 39 public: 40 enum Type { 41 Normal, 42 RW, 43#ifndef __APPLE__ 44 Spin 45#else 46 Spin = Normal 47#endif 48 }; 49 50 explicit UserMutex(Type type = Normal); 51 ~UserMutex(); 52 53 void Init(); 54 void StaticInit(); // Emulates static initialization (tsan invisible). 55 void Destroy(); 56 void Lock(); 57 bool TryLock(); 58 void Unlock(); 59 void ReadLock(); 60 bool TryReadLock(); 61 void ReadUnlock(); 62 63 private: 64 // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever. 65 void *mtx_[128]; 66 bool alive_; 67 const Type type_; 68 69 UserMutex(const UserMutex &); 70 void operator=(const UserMutex &); 71}; 72 73// A thread is started in CTOR and joined in DTOR. 74class ScopedThread { 75 public: 76 explicit ScopedThread(bool detached = false, bool main = false); 77 ~ScopedThread(); 78 void Detach(); 79 80 void Access(void *addr, bool is_write, int size, bool expect_race); 81 void Read(const MemLoc &ml, int size, bool expect_race = false) { 82 Access(ml.loc(), false, size, expect_race); 83 } 84 void Write(const MemLoc &ml, int size, bool expect_race = false) { 85 Access(ml.loc(), true, size, expect_race); 86 } 87 void Read1(const MemLoc &ml, bool expect_race = false) { 88 Read(ml, 1, expect_race); } 89 void Read2(const MemLoc &ml, bool expect_race = false) { 90 Read(ml, 2, expect_race); } 91 void Read4(const MemLoc &ml, bool expect_race = false) { 92 Read(ml, 4, expect_race); } 93 void Read8(const MemLoc &ml, bool expect_race = false) { 94 Read(ml, 8, expect_race); } 95 void Write1(const MemLoc &ml, bool expect_race = false) { 96 Write(ml, 1, expect_race); } 97 void Write2(const MemLoc &ml, bool expect_race = false) { 98 Write(ml, 2, expect_race); } 99 void Write4(const MemLoc &ml, bool expect_race = false) { 100 Write(ml, 4, expect_race); } 101 void Write8(const MemLoc &ml, bool expect_race = false) { 102 Write(ml, 8, expect_race); } 103 104 void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val, 105 bool expect_race = false); 106 107 void Call(void(*pc)()); 108 void Return(); 109 110 void Create(const UserMutex &m); 111 void Destroy(const UserMutex &m); 112 void Lock(const UserMutex &m); 113 bool TryLock(const UserMutex &m); 114 void Unlock(const UserMutex &m); 115 void ReadLock(const UserMutex &m); 116 bool TryReadLock(const UserMutex &m); 117 void ReadUnlock(const UserMutex &m); 118 119 void Memcpy(void *dst, const void *src, int size, bool expect_race = false); 120 void Memset(void *dst, int val, int size, bool expect_race = false); 121 122 private: 123 struct Impl; 124 Impl *impl_; 125 ScopedThread(const ScopedThread&); // Not implemented. 126 void operator = (const ScopedThread&); // Not implemented. 127}; 128 129class MainThread : public ScopedThread { 130 public: 131 MainThread() 132 : ScopedThread(false, true) { 133 } 134}; 135 136#endif // #ifndef TSAN_TEST_UTIL_H 137