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