tsan_sync.cc revision 238901
1238901Sandrew//===-- tsan_sync.cc ------------------------------------------------------===// 2238901Sandrew// 3238901Sandrew// The LLVM Compiler Infrastructure 4238901Sandrew// 5238901Sandrew// This file is distributed under the University of Illinois Open Source 6238901Sandrew// License. See LICENSE.TXT for details. 7238901Sandrew// 8238901Sandrew//===----------------------------------------------------------------------===// 9238901Sandrew// 10238901Sandrew// This file is a part of ThreadSanitizer (TSan), a race detector. 11238901Sandrew// 12238901Sandrew//===----------------------------------------------------------------------===// 13238901Sandrew#include "sanitizer_common/sanitizer_placement_new.h" 14238901Sandrew#include "tsan_sync.h" 15238901Sandrew#include "tsan_rtl.h" 16238901Sandrew#include "tsan_mman.h" 17238901Sandrew 18238901Sandrewnamespace __tsan { 19238901Sandrew 20238901SandrewSyncVar::SyncVar(uptr addr) 21238901Sandrew : mtx(MutexTypeSyncVar, StatMtxSyncVar) 22238901Sandrew , addr(addr) 23238901Sandrew , owner_tid(kInvalidTid) 24238901Sandrew , recursion() 25238901Sandrew , is_rw() 26238901Sandrew , is_recursive() 27238901Sandrew , is_broken() { 28238901Sandrew} 29238901Sandrew 30238901SandrewSyncTab::Part::Part() 31238901Sandrew : mtx(MutexTypeSyncTab, StatMtxSyncTab) 32238901Sandrew , val() { 33238901Sandrew} 34238901Sandrew 35238901SandrewSyncTab::SyncTab() { 36238901Sandrew} 37238901Sandrew 38238901SandrewSyncTab::~SyncTab() { 39238901Sandrew for (int i = 0; i < kPartCount; i++) { 40238901Sandrew while (tab_[i].val) { 41238901Sandrew SyncVar *tmp = tab_[i].val; 42238901Sandrew tab_[i].val = tmp->next; 43238901Sandrew DestroyAndFree(tmp); 44238901Sandrew } 45238901Sandrew } 46238901Sandrew} 47238901Sandrew 48238901SandrewSyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc, 49238901Sandrew uptr addr, bool write_lock) { 50238901Sandrew Part *p = &tab_[PartIdx(addr)]; 51238901Sandrew { 52238901Sandrew ReadLock l(&p->mtx); 53238901Sandrew for (SyncVar *res = p->val; res; res = res->next) { 54238901Sandrew if (res->addr == addr) { 55238901Sandrew if (write_lock) 56238901Sandrew res->mtx.Lock(); 57238901Sandrew else 58238901Sandrew res->mtx.ReadLock(); 59238901Sandrew return res; 60238901Sandrew } 61238901Sandrew } 62238901Sandrew } 63238901Sandrew { 64238901Sandrew Lock l(&p->mtx); 65238901Sandrew SyncVar *res = p->val; 66238901Sandrew for (; res; res = res->next) { 67238901Sandrew if (res->addr == addr) 68238901Sandrew break; 69238901Sandrew } 70238901Sandrew if (res == 0) { 71238901Sandrew StatInc(thr, StatSyncCreated); 72238901Sandrew void *mem = internal_alloc(MBlockSync, sizeof(SyncVar)); 73238901Sandrew res = new(mem) SyncVar(addr); 74238901Sandrew#ifndef TSAN_GO 75238901Sandrew res->creation_stack.ObtainCurrent(thr, pc); 76238901Sandrew#endif 77238901Sandrew res->next = p->val; 78238901Sandrew p->val = res; 79238901Sandrew } 80238901Sandrew if (write_lock) 81238901Sandrew res->mtx.Lock(); 82238901Sandrew else 83238901Sandrew res->mtx.ReadLock(); 84238901Sandrew return res; 85238901Sandrew } 86238901Sandrew} 87238901Sandrew 88238901SandrewSyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) { 89238901Sandrew Part *p = &tab_[PartIdx(addr)]; 90238901Sandrew SyncVar *res = 0; 91238901Sandrew { 92238901Sandrew Lock l(&p->mtx); 93238901Sandrew SyncVar **prev = &p->val; 94238901Sandrew res = *prev; 95238901Sandrew while (res) { 96238901Sandrew if (res->addr == addr) { 97238901Sandrew *prev = res->next; 98238901Sandrew break; 99238901Sandrew } 100238901Sandrew prev = &res->next; 101238901Sandrew res = *prev; 102238901Sandrew } 103238901Sandrew } 104238901Sandrew if (res) { 105238901Sandrew StatInc(thr, StatSyncDestroyed); 106238901Sandrew res->mtx.Lock(); 107238901Sandrew res->mtx.Unlock(); 108238901Sandrew } 109238901Sandrew return res; 110238901Sandrew} 111238901Sandrew 112238901Sandrewuptr SyncVar::GetMemoryConsumption() { 113238901Sandrew return sizeof(*this) 114238901Sandrew + clock.size() * sizeof(u64) 115238901Sandrew + read_clock.size() * sizeof(u64) 116238901Sandrew + creation_stack.Size() * sizeof(uptr); 117238901Sandrew} 118238901Sandrew 119238901Sandrewuptr SyncTab::GetMemoryConsumption(uptr *nsync) { 120238901Sandrew uptr mem = 0; 121238901Sandrew for (int i = 0; i < kPartCount; i++) { 122238901Sandrew Part *p = &tab_[i]; 123238901Sandrew Lock l(&p->mtx); 124238901Sandrew for (SyncVar *s = p->val; s; s = s->next) { 125238901Sandrew *nsync += 1; 126238901Sandrew mem += s->GetMemoryConsumption(); 127238901Sandrew } 128238901Sandrew } 129238901Sandrew return mem; 130238901Sandrew} 131238901Sandrew 132238901Sandrewint SyncTab::PartIdx(uptr addr) { 133238901Sandrew return (addr >> 3) % kPartCount; 134238901Sandrew} 135238901Sandrew 136238901SandrewStackTrace::StackTrace() 137238901Sandrew : n_() 138238901Sandrew , s_() 139238901Sandrew , c_() { 140238901Sandrew} 141238901Sandrew 142238901SandrewStackTrace::StackTrace(uptr *buf, uptr cnt) 143238901Sandrew : n_() 144238901Sandrew , s_(buf) 145238901Sandrew , c_(cnt) { 146238901Sandrew CHECK_NE(buf, 0); 147238901Sandrew CHECK_NE(cnt, 0); 148238901Sandrew} 149238901Sandrew 150238901SandrewStackTrace::~StackTrace() { 151238901Sandrew Reset(); 152238901Sandrew} 153238901Sandrew 154238901Sandrewvoid StackTrace::Reset() { 155238901Sandrew if (s_ && !c_) { 156238901Sandrew CHECK_NE(n_, 0); 157238901Sandrew internal_free(s_); 158238901Sandrew s_ = 0; 159238901Sandrew } 160238901Sandrew n_ = 0; 161238901Sandrew} 162238901Sandrew 163238901Sandrewvoid StackTrace::Init(const uptr *pcs, uptr cnt) { 164238901Sandrew Reset(); 165238901Sandrew if (cnt == 0) 166238901Sandrew return; 167238901Sandrew if (c_) { 168238901Sandrew CHECK_NE(s_, 0); 169238901Sandrew CHECK_LE(cnt, c_); 170238901Sandrew } else { 171238901Sandrew s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0])); 172238901Sandrew } 173238901Sandrew n_ = cnt; 174238901Sandrew internal_memcpy(s_, pcs, cnt * sizeof(s_[0])); 175238901Sandrew} 176238901Sandrew 177238901Sandrewvoid StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) { 178238901Sandrew Reset(); 179238901Sandrew n_ = thr->shadow_stack_pos - thr->shadow_stack; 180238901Sandrew if (n_ + !!toppc == 0) 181238901Sandrew return; 182238901Sandrew if (c_) { 183238901Sandrew CHECK_NE(s_, 0); 184238901Sandrew CHECK_LE(n_ + !!toppc, c_); 185238901Sandrew } else { 186238901Sandrew s_ = (uptr*)internal_alloc(MBlockStackTrace, 187238901Sandrew (n_ + !!toppc) * sizeof(s_[0])); 188238901Sandrew } 189238901Sandrew for (uptr i = 0; i < n_; i++) 190238901Sandrew s_[i] = thr->shadow_stack[i]; 191238901Sandrew if (toppc) { 192238901Sandrew s_[n_] = toppc; 193238901Sandrew n_++; 194238901Sandrew } 195238901Sandrew} 196238901Sandrew 197238901Sandrewvoid StackTrace::CopyFrom(const StackTrace& other) { 198238901Sandrew Reset(); 199238901Sandrew Init(other.Begin(), other.Size()); 200238901Sandrew} 201238901Sandrew 202238901Sandrewbool StackTrace::IsEmpty() const { 203238901Sandrew return n_ == 0; 204238901Sandrew} 205238901Sandrew 206238901Sandrewuptr StackTrace::Size() const { 207238901Sandrew return n_; 208238901Sandrew} 209238901Sandrew 210238901Sandrewuptr StackTrace::Get(uptr i) const { 211238901Sandrew CHECK_LT(i, n_); 212238901Sandrew return s_[i]; 213238901Sandrew} 214238901Sandrew 215238901Sandrewconst uptr *StackTrace::Begin() const { 216238901Sandrew return s_; 217238901Sandrew} 218238901Sandrew 219238901Sandrew} // namespace __tsan 220