1 //===-- tsan_sync.cc ------------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
11 #include "sanitizer_common/sanitizer_placement_new.h"
12 #include "tsan_sync.h"
14 #include "tsan_mman.h"
18 SyncVar::SyncVar(uptr addr
, u64 uid
)
19 : mtx(MutexTypeSyncVar
, StatMtxSyncVar
)
22 , owner_tid(kInvalidTid
)
32 : mtx(MutexTypeSyncTab
, StatMtxSyncTab
)
40 for (int i
= 0; i
< kPartCount
; i
++) {
42 SyncVar
*tmp
= tab_
[i
].val
;
43 tab_
[i
].val
= tmp
->next
;
49 SyncVar
* SyncTab::GetOrCreateAndLock(ThreadState
*thr
, uptr pc
,
50 uptr addr
, bool write_lock
) {
51 return GetAndLock(thr
, pc
, addr
, write_lock
, true);
54 SyncVar
* SyncTab::GetIfExistsAndLock(uptr addr
, bool write_lock
) {
55 return GetAndLock(0, 0, addr
, write_lock
, false);
58 SyncVar
* SyncTab::Create(ThreadState
*thr
, uptr pc
, uptr addr
) {
59 StatInc(thr
, StatSyncCreated
);
60 void *mem
= internal_alloc(MBlockSync
, sizeof(SyncVar
));
61 const u64 uid
= atomic_fetch_add(&uid_gen_
, 1, memory_order_relaxed
);
62 SyncVar
*res
= new(mem
) SyncVar(addr
, uid
);
64 res
->creation_stack
.ObtainCurrent(thr
, pc
);
69 SyncVar
* SyncTab::GetAndLock(ThreadState
*thr
, uptr pc
,
70 uptr addr
, bool write_lock
, bool create
) {
73 SyncVar
*res
= GetJavaSync(thr
, pc
, addr
, write_lock
, create
);
78 // Here we ask only PrimaryAllocator, because
79 // SecondaryAllocator::PointerIsMine() is slow and we have fallback on
80 // the hashmap anyway.
81 if (PrimaryAllocator::PointerIsMine((void*)addr
)) {
82 MBlock
*b
= user_mblock(thr
, (void*)addr
);
85 for (res
= b
->head
; res
; res
= res
->next
) {
86 if (res
->addr
== addr
)
92 res
= Create(thr
, pc
, addr
);
104 Part
*p
= &tab_
[PartIdx(addr
)];
107 for (SyncVar
*res
= p
->val
; res
; res
= res
->next
) {
108 if (res
->addr
== addr
) {
121 SyncVar
*res
= p
->val
;
122 for (; res
; res
= res
->next
) {
123 if (res
->addr
== addr
)
127 res
= Create(thr
, pc
, addr
);
139 SyncVar
* SyncTab::GetAndRemove(ThreadState
*thr
, uptr pc
, uptr addr
) {
142 SyncVar
*res
= GetAndRemoveJavaSync(thr
, pc
, addr
);
146 if (PrimaryAllocator::PointerIsMine((void*)addr
)) {
147 MBlock
*b
= user_mblock(thr
, (void*)addr
);
151 SyncVar
**prev
= &b
->head
;
154 if (res
->addr
== addr
) {
155 if (res
->is_linker_init
)
165 StatInc(thr
, StatSyncDestroyed
);
173 Part
*p
= &tab_
[PartIdx(addr
)];
177 SyncVar
**prev
= &p
->val
;
180 if (res
->addr
== addr
) {
181 if (res
->is_linker_init
)
191 StatInc(thr
, StatSyncDestroyed
);
198 uptr
SyncVar::GetMemoryConsumption() {
200 + clock
.size() * sizeof(u64
)
201 + read_clock
.size() * sizeof(u64
)
202 + creation_stack
.Size() * sizeof(uptr
);
205 uptr
SyncTab::GetMemoryConsumption(uptr
*nsync
) {
207 for (int i
= 0; i
< kPartCount
; i
++) {
210 for (SyncVar
*s
= p
->val
; s
; s
= s
->next
) {
212 mem
+= s
->GetMemoryConsumption();
218 int SyncTab::PartIdx(uptr addr
) {
219 return (addr
>> 3) % kPartCount
;
222 StackTrace::StackTrace()
228 StackTrace::StackTrace(uptr
*buf
, uptr cnt
)
236 StackTrace::~StackTrace() {
240 void StackTrace::Reset() {
249 void StackTrace::Init(const uptr
*pcs
, uptr cnt
) {
257 s_
= (uptr
*)internal_alloc(MBlockStackTrace
, cnt
* sizeof(s_
[0]));
260 internal_memcpy(s_
, pcs
, cnt
* sizeof(s_
[0]));
263 void StackTrace::ObtainCurrent(ThreadState
*thr
, uptr toppc
) {
265 n_
= thr
->shadow_stack_pos
- thr
->shadow_stack
;
266 if (n_
+ !!toppc
== 0)
271 if (n_
+ !!toppc
> c_
) {
272 start
= n_
- c_
+ !!toppc
;
276 s_
= (uptr
*)internal_alloc(MBlockStackTrace
,
277 (n_
+ !!toppc
) * sizeof(s_
[0]));
279 for (uptr i
= 0; i
< n_
; i
++)
280 s_
[i
] = thr
->shadow_stack
[start
+ i
];
287 void StackTrace::CopyFrom(const StackTrace
& other
) {
289 Init(other
.Begin(), other
.Size());
292 bool StackTrace::IsEmpty() const {
296 uptr
StackTrace::Size() const {
300 uptr
StackTrace::Get(uptr i
) const {
305 const uptr
*StackTrace::Begin() const {
309 } // namespace __tsan