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 18 class ThreadSanitizer : public ::testing::Test { 19 protected: 20 void TearDown() override; 21 }; 22 23 void TestMutexBeforeInit(); 24 25 // A location of memory on which a race may be detected. 26 class MemLoc { 27 public: 28 explicit MemLoc(int offset_from_aligned = 0); MemLoc(void * const real_addr)29 explicit MemLoc(void *const real_addr) : loc_(real_addr) { } 30 ~MemLoc(); loc()31 void *loc() const { return loc_; } 32 private: 33 void *const loc_; 34 MemLoc(const MemLoc&); 35 void operator = (const MemLoc&); 36 }; 37 38 class 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. 74 class 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 129 class MainThread : public ScopedThread { 130 public: MainThread()131 MainThread() 132 : ScopedThread(false, true) { 133 } 134 }; 135 136 #endif // #ifndef TSAN_TEST_UTIL_H 137