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 void TestMutexBeforeInit(); 17 18 // A location of memory on which a race may be detected. 19 class MemLoc { 20 public: 21 explicit MemLoc(int offset_from_aligned = 0); 22 explicit MemLoc(void *const real_addr) : loc_(real_addr) { } 23 ~MemLoc(); 24 void *loc() const { return loc_; } 25 private: 26 void *const loc_; 27 MemLoc(const MemLoc&); 28 void operator = (const MemLoc&); 29 }; 30 31 class Mutex { 32 public: 33 enum Type { 34 Normal, 35 RW, 36 #ifndef __APPLE__ 37 Spin 38 #else 39 Spin = Normal 40 #endif 41 }; 42 43 explicit Mutex(Type type = Normal); 44 ~Mutex(); 45 46 void Init(); 47 void StaticInit(); // Emulates static initialization (tsan invisible). 48 void Destroy(); 49 void Lock(); 50 bool TryLock(); 51 void Unlock(); 52 void ReadLock(); 53 bool TryReadLock(); 54 void ReadUnlock(); 55 56 private: 57 // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever. 58 void *mtx_[128]; 59 bool alive_; 60 const Type type_; 61 62 Mutex(const Mutex&); 63 void operator = (const Mutex&); 64 }; 65 66 // A thread is started in CTOR and joined in DTOR. 67 class ScopedThread { 68 public: 69 explicit ScopedThread(bool detached = false, bool main = false); 70 ~ScopedThread(); 71 void Detach(); 72 73 void Access(void *addr, bool is_write, int size, bool expect_race); 74 void Read(const MemLoc &ml, int size, bool expect_race = false) { 75 Access(ml.loc(), false, size, expect_race); 76 } 77 void Write(const MemLoc &ml, int size, bool expect_race = false) { 78 Access(ml.loc(), true, size, expect_race); 79 } 80 void Read1(const MemLoc &ml, bool expect_race = false) { 81 Read(ml, 1, expect_race); } 82 void Read2(const MemLoc &ml, bool expect_race = false) { 83 Read(ml, 2, expect_race); } 84 void Read4(const MemLoc &ml, bool expect_race = false) { 85 Read(ml, 4, expect_race); } 86 void Read8(const MemLoc &ml, bool expect_race = false) { 87 Read(ml, 8, expect_race); } 88 void Write1(const MemLoc &ml, bool expect_race = false) { 89 Write(ml, 1, expect_race); } 90 void Write2(const MemLoc &ml, bool expect_race = false) { 91 Write(ml, 2, expect_race); } 92 void Write4(const MemLoc &ml, bool expect_race = false) { 93 Write(ml, 4, expect_race); } 94 void Write8(const MemLoc &ml, bool expect_race = false) { 95 Write(ml, 8, expect_race); } 96 97 void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val, 98 bool expect_race = false); 99 100 void Call(void(*pc)()); 101 void Return(); 102 103 void Create(const Mutex &m); 104 void Destroy(const Mutex &m); 105 void Lock(const Mutex &m); 106 bool TryLock(const Mutex &m); 107 void Unlock(const Mutex &m); 108 void ReadLock(const Mutex &m); 109 bool TryReadLock(const Mutex &m); 110 void ReadUnlock(const Mutex &m); 111 112 void Memcpy(void *dst, const void *src, int size, bool expect_race = false); 113 void Memset(void *dst, int val, int size, bool expect_race = false); 114 115 private: 116 struct Impl; 117 Impl *impl_; 118 ScopedThread(const ScopedThread&); // Not implemented. 119 void operator = (const ScopedThread&); // Not implemented. 120 }; 121 122 class MainThread : public ScopedThread { 123 public: 124 MainThread() 125 : ScopedThread(false, true) { 126 } 127 }; 128 129 #endif // #ifndef TSAN_TEST_UTIL_H 130