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 "sanitizer_common/sanitizer_deadlock_detector_interface.h"
19 #include "tsan_defs.h"
20 #include "tsan_clock.h"
21 #include "tsan_mutex.h"
22 #include "tsan_dense_alloc.h"
23 
24 namespace __tsan {
25 
26 struct SyncVar {
27   SyncVar();
28 
29   static const int kInvalidTid = -1;
30 
31   uptr addr;  // overwritten by DenseSlabAlloc freelist
32   Mutex mtx;
33   u64 uid;  // Globally unique id.
34   u32 creation_stack_id;
35   int owner_tid;  // Set only by exclusive owners.
36   u64 last_lock;
37   int recursion;
38   bool is_rw;
39   bool is_recursive;
40   bool is_broken;
41   bool is_linker_init;
42   u32 next;  // in MetaMap
43   DDMutex dd;
44   SyncClock read_clock;  // Used for rw mutexes only.
45   // The clock is placed last, so that it is situated on a different cache line
46   // with the mtx. This reduces contention for hot sync objects.
47   SyncClock clock;
48 
49   void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid);
50   void Reset(ThreadState *thr);
51 
GetIdSyncVar52   u64 GetId() const {
53     // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
54     return GetLsb((u64)addr | (uid << 47), 61);
55   }
CheckIdSyncVar56   bool CheckId(u64 uid) const {
57     CHECK_EQ(uid, GetLsb(uid, 14));
58     return GetLsb(this->uid, 14) == uid;
59   }
SplitIdSyncVar60   static uptr SplitId(u64 id, u64 *uid) {
61     *uid = id >> 47;
62     return (uptr)GetLsb(id, 47);
63   }
64 };
65 
66 /* MetaMap allows to map arbitrary user pointers onto various descriptors.
67    Currently it maps pointers to heap block descriptors and sync var descs.
68    It uses 1/2 direct shadow, see tsan_platform.h.
69 */
70 class MetaMap {
71  public:
72   MetaMap();
73 
74   void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
75   uptr FreeBlock(ThreadState *thr, uptr pc, uptr p);
76   bool FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
77   void ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
78   MBlock* GetBlock(uptr p);
79 
80   SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
81                               uptr addr, bool write_lock);
82   SyncVar* GetIfExistsAndLock(uptr addr);
83 
84   void MoveMemory(uptr src, uptr dst, uptr sz);
85 
86   void OnThreadIdle(ThreadState *thr);
87 
88  private:
89   static const u32 kFlagMask  = 3 << 30;
90   static const u32 kFlagBlock = 1 << 30;
91   static const u32 kFlagSync  = 2 << 30;
92   typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
93   typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
94   BlockAlloc block_alloc_;
95   SyncAlloc sync_alloc_;
96   atomic_uint64_t uid_gen_;
97 
98   SyncVar* GetAndLock(ThreadState *thr, uptr pc, uptr addr, bool write_lock,
99                       bool create);
100 };
101 
102 }  // namespace __tsan
103 
104 #endif  // TSAN_SYNC_H
105