tsan_sync.h revision 1.3
1//===-- tsan_sync.h ---------------------------------------------*- C++ -*-===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is a part of ThreadSanitizer (TSan), a race detector.
9//
10//===----------------------------------------------------------------------===//
11#ifndef TSAN_SYNC_H
12#define TSAN_SYNC_H
13
14#include "sanitizer_common/sanitizer_atomic.h"
15#include "sanitizer_common/sanitizer_common.h"
16#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
17#include "tsan_defs.h"
18#include "tsan_clock.h"
19#include "tsan_dense_alloc.h"
20
21namespace __tsan {
22
23// These need to match __tsan_mutex_* flags defined in tsan_interface.h.
24// See documentation there as well.
25enum MutexFlags {
26  MutexFlagLinkerInit          = 1 << 0, // __tsan_mutex_linker_init
27  MutexFlagWriteReentrant      = 1 << 1, // __tsan_mutex_write_reentrant
28  MutexFlagReadReentrant       = 1 << 2, // __tsan_mutex_read_reentrant
29  MutexFlagReadLock            = 1 << 3, // __tsan_mutex_read_lock
30  MutexFlagTryLock             = 1 << 4, // __tsan_mutex_try_lock
31  MutexFlagTryLockFailed       = 1 << 5, // __tsan_mutex_try_lock_failed
32  MutexFlagRecursiveLock       = 1 << 6, // __tsan_mutex_recursive_lock
33  MutexFlagRecursiveUnlock     = 1 << 7, // __tsan_mutex_recursive_unlock
34  MutexFlagNotStatic           = 1 << 8, // __tsan_mutex_not_static
35
36  // The following flags are runtime private.
37  // Mutex API misuse was detected, so don't report any more.
38  MutexFlagBroken              = 1 << 30,
39  // We did not intercept pre lock event, so handle it on post lock.
40  MutexFlagDoPreLockOnPostLock = 1 << 29,
41  // Must list all mutex creation flags.
42  MutexCreationFlagMask        = MutexFlagLinkerInit |
43                                 MutexFlagWriteReentrant |
44                                 MutexFlagReadReentrant |
45                                 MutexFlagNotStatic,
46};
47
48// SyncVar is a descriptor of a user synchronization object
49// (mutex or an atomic variable).
50struct SyncVar {
51  SyncVar();
52
53  uptr addr;  // overwritten by DenseSlabAlloc freelist
54  Mutex mtx;
55  u64 uid;  // Globally unique id.
56  StackID creation_stack_id;
57  Tid owner_tid;  // Set only by exclusive owners.
58  u64 last_lock;
59  int recursion;
60  atomic_uint32_t flags;
61  u32 next;  // in MetaMap
62  DDMutex dd;
63  SyncClock read_clock;  // Used for rw mutexes only.
64  // The clock is placed last, so that it is situated on a different cache line
65  // with the mtx. This reduces contention for hot sync objects.
66  SyncClock clock;
67
68  void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid, bool save_stack);
69  void Reset(Processor *proc);
70
71  u64 GetId() const {
72    // 48 lsb is addr, then 14 bits is low part of uid, then 2 zero bits.
73    return GetLsb((u64)addr | (uid << 48), 60);
74  }
75  bool CheckId(u64 uid) const {
76    CHECK_EQ(uid, GetLsb(uid, 14));
77    return GetLsb(this->uid, 14) == uid;
78  }
79  static uptr SplitId(u64 id, u64 *uid) {
80    *uid = id >> 48;
81    return (uptr)GetLsb(id, 48);
82  }
83
84  bool IsFlagSet(u32 f) const {
85    return atomic_load_relaxed(&flags) & f;
86  }
87
88  void SetFlags(u32 f) {
89    atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f);
90  }
91
92  void UpdateFlags(u32 flagz) {
93    // Filter out operation flags.
94    if (!(flagz & MutexCreationFlagMask))
95      return;
96    u32 current = atomic_load_relaxed(&flags);
97    if (current & MutexCreationFlagMask)
98      return;
99    // Note: this can be called from MutexPostReadLock which holds only read
100    // lock on the SyncVar.
101    atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask));
102  }
103};
104
105// MetaMap maps app addresses to heap block (MBlock) and sync var (SyncVar)
106// descriptors. It uses 1/2 direct shadow, see tsan_platform.h for the mapping.
107class MetaMap {
108 public:
109  MetaMap();
110
111  void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
112  uptr FreeBlock(Processor *proc, uptr p);
113  bool FreeRange(Processor *proc, uptr p, uptr sz);
114  void ResetRange(Processor *proc, uptr p, uptr sz);
115  MBlock* GetBlock(uptr p);
116
117  SyncVar *GetSyncOrCreate(ThreadState *thr, uptr pc, uptr addr,
118                           bool save_stack) {
119    return GetSync(thr, pc, addr, true, save_stack);
120  }
121  SyncVar *GetSyncIfExists(uptr addr) {
122    return GetSync(nullptr, 0, addr, false, false);
123  }
124
125  void MoveMemory(uptr src, uptr dst, uptr sz);
126
127  void OnProcIdle(Processor *proc);
128
129  struct MemoryStats {
130    uptr mem_block;
131    uptr sync_obj;
132  };
133
134  MemoryStats GetMemoryStats() const;
135
136 private:
137  static const u32 kFlagMask  = 3u << 30;
138  static const u32 kFlagBlock = 1u << 30;
139  static const u32 kFlagSync  = 2u << 30;
140  typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
141  typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
142  BlockAlloc block_alloc_;
143  SyncAlloc sync_alloc_;
144  atomic_uint64_t uid_gen_;
145
146  SyncVar *GetSync(ThreadState *thr, uptr pc, uptr addr, bool create,
147                   bool save_stack);
148};
149
150}  // namespace __tsan
151
152#endif  // TSAN_SYNC_H
153