1//===-- tsan_sync.h ---------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13#ifndef TSAN_SYNC_H
14#define TSAN_SYNC_H
15
16#include "sanitizer_common/sanitizer_atomic.h"
17#include "sanitizer_common/sanitizer_common.h"
18#include "tsan_clock.h"
19#include "tsan_defs.h"
20#include "tsan_mutex.h"
21
22namespace __tsan {
23
24class SlabCache;
25
26class StackTrace {
27 public:
28  StackTrace();
29  // Initialized the object in "static mode",
30  // in this mode it never calls malloc/free but uses the provided buffer.
31  StackTrace(uptr *buf, uptr cnt);
32  ~StackTrace();
33  void Reset();
34
35  void Init(const uptr *pcs, uptr cnt);
36  void ObtainCurrent(ThreadState *thr, uptr toppc);
37  bool IsEmpty() const;
38  uptr Size() const;
39  uptr Get(uptr i) const;
40  const uptr *Begin() const;
41  void CopyFrom(const StackTrace& other);
42
43 private:
44  uptr n_;
45  uptr *s_;
46  const uptr c_;
47
48  StackTrace(const StackTrace&);
49  void operator = (const StackTrace&);
50};
51
52struct SyncVar {
53  explicit SyncVar(uptr addr, u64 uid);
54
55  static const int kInvalidTid = -1;
56
57  Mutex mtx;
58  uptr addr;
59  const u64 uid;  // Globally unique id.
60  SyncClock clock;
61  SyncClock read_clock;  // Used for rw mutexes only.
62  u32 creation_stack_id;
63  int owner_tid;  // Set only by exclusive owners.
64  u64 last_lock;
65  int recursion;
66  bool is_rw;
67  bool is_recursive;
68  bool is_broken;
69  bool is_linker_init;
70  SyncVar *next;  // In SyncTab hashtable.
71
72  uptr GetMemoryConsumption();
73  u64 GetId() const {
74    // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
75    return GetLsb((u64)addr | (uid << 47), 61);
76  }
77  bool CheckId(u64 uid) const {
78    CHECK_EQ(uid, GetLsb(uid, 14));
79    return GetLsb(this->uid, 14) == uid;
80  }
81  static uptr SplitId(u64 id, u64 *uid) {
82    *uid = id >> 47;
83    return (uptr)GetLsb(id, 47);
84  }
85};
86
87class SyncTab {
88 public:
89  SyncTab();
90  ~SyncTab();
91
92  SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
93                              uptr addr, bool write_lock);
94  SyncVar* GetIfExistsAndLock(uptr addr, bool write_lock);
95
96  // If the SyncVar does not exist, returns 0.
97  SyncVar* GetAndRemove(ThreadState *thr, uptr pc, uptr addr);
98
99  SyncVar* Create(ThreadState *thr, uptr pc, uptr addr);
100
101  uptr GetMemoryConsumption(uptr *nsync);
102
103 private:
104  struct Part {
105    Mutex mtx;
106    SyncVar *val;
107    char pad[kCacheLineSize - sizeof(Mutex) - sizeof(SyncVar*)];  // NOLINT
108    Part();
109  };
110
111  // FIXME: Implement something more sane.
112  static const int kPartCount = 1009;
113  Part tab_[kPartCount];
114  atomic_uint64_t uid_gen_;
115
116  int PartIdx(uptr addr);
117
118  SyncVar* GetAndLock(ThreadState *thr, uptr pc,
119                      uptr addr, bool write_lock, bool create);
120
121  SyncTab(const SyncTab&);  // Not implemented.
122  void operator = (const SyncTab&);  // Not implemented.
123};
124
125}  // namespace __tsan
126
127#endif  // TSAN_SYNC_H
128