summaryrefslogtreecommitdiff
path: root/lib/tsan/tests/rtl/tsan_test_util.h
blob: 31b1b188f6247b65db0bfad06e12999b37f7433d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//===-- tsan_test_util.h ----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// Test utils.
//===----------------------------------------------------------------------===//
#ifndef TSAN_TEST_UTIL_H
#define TSAN_TEST_UTIL_H

void TestMutexBeforeInit();

// A location of memory on which a race may be detected.
class MemLoc {
 public:
  explicit MemLoc(int offset_from_aligned = 0);
  explicit MemLoc(void *const real_addr) : loc_(real_addr) { }
  ~MemLoc();
  void *loc() const { return loc_; }
 private:
  void *const loc_;
  MemLoc(const MemLoc&);
  void operator = (const MemLoc&);
};

class Mutex {
 public:
  enum Type {
    Normal,
    RW,
#ifndef __APPLE__
    Spin
#else
    Spin = Normal
#endif
  };

  explicit Mutex(Type type = Normal);
  ~Mutex();

  void Init();
  void StaticInit();  // Emulates static initialization (tsan invisible).
  void Destroy();
  void Lock();
  bool TryLock();
  void Unlock();
  void ReadLock();
  bool TryReadLock();
  void ReadUnlock();

 private:
  // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever.
  void *mtx_[128];
  bool alive_;
  const Type type_;

  Mutex(const Mutex&);
  void operator = (const Mutex&);
};

// A thread is started in CTOR and joined in DTOR.
class ScopedThread {
 public:
  explicit ScopedThread(bool detached = false, bool main = false);
  ~ScopedThread();
  void Detach();

  void Access(void *addr, bool is_write, int size, bool expect_race);
  void Read(const MemLoc &ml, int size, bool expect_race = false) {
    Access(ml.loc(), false, size, expect_race);
  }
  void Write(const MemLoc &ml, int size, bool expect_race = false) {
    Access(ml.loc(), true, size, expect_race);
  }
  void Read1(const MemLoc &ml, bool expect_race = false) {
    Read(ml, 1, expect_race); }
  void Read2(const MemLoc &ml, bool expect_race = false) {
    Read(ml, 2, expect_race); }
  void Read4(const MemLoc &ml, bool expect_race = false) {
    Read(ml, 4, expect_race); }
  void Read8(const MemLoc &ml, bool expect_race = false) {
    Read(ml, 8, expect_race); }
  void Write1(const MemLoc &ml, bool expect_race = false) {
    Write(ml, 1, expect_race); }
  void Write2(const MemLoc &ml, bool expect_race = false) {
    Write(ml, 2, expect_race); }
  void Write4(const MemLoc &ml, bool expect_race = false) {
    Write(ml, 4, expect_race); }
  void Write8(const MemLoc &ml, bool expect_race = false) {
    Write(ml, 8, expect_race); }

  void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val,
                  bool expect_race = false);

  void Call(void(*pc)());
  void Return();

  void Create(const Mutex &m);
  void Destroy(const Mutex &m);
  void Lock(const Mutex &m);
  bool TryLock(const Mutex &m);
  void Unlock(const Mutex &m);
  void ReadLock(const Mutex &m);
  bool TryReadLock(const Mutex &m);
  void ReadUnlock(const Mutex &m);

  void Memcpy(void *dst, const void *src, int size, bool expect_race = false);
  void Memset(void *dst, int val, int size, bool expect_race = false);

 private:
  struct Impl;
  Impl *impl_;
  ScopedThread(const ScopedThread&);  // Not implemented.
  void operator = (const ScopedThread&);  // Not implemented.
};

class MainThread : public ScopedThread {
 public:
  MainThread()
    : ScopedThread(false, true) {
  }
};

#endif  // #ifndef TSAN_TEST_UTIL_H