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