xref: /llvm-project/compiler-rt/lib/tsan/tests/rtl/tsan_test_util.h (revision a61c8e1ebdff2111a394feac168426e0d962a134)
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