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