Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_sync.cc ------------------------------------------------------===//
      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 #include "sanitizer_common/sanitizer_placement_new.h"
     14 #include "tsan_sync.h"
     15 #include "tsan_rtl.h"
     16 #include "tsan_mman.h"
     17 
     18 namespace __tsan {
     19 
     20 SyncVar::SyncVar(uptr addr)
     21   : mtx(MutexTypeSyncVar, StatMtxSyncVar)
     22   , addr(addr)
     23   , owner_tid(kInvalidTid)
     24   , last_lock()
     25   , recursion()
     26   , is_rw()
     27   , is_recursive()
     28   , is_broken()
     29   , is_linker_init() {
     30 }
     31 
     32 SyncTab::Part::Part()
     33   : mtx(MutexTypeSyncTab, StatMtxSyncTab)
     34   , val() {
     35 }
     36 
     37 SyncTab::SyncTab() {
     38 }
     39 
     40 SyncTab::~SyncTab() {
     41   for (int i = 0; i < kPartCount; i++) {
     42     while (tab_[i].val) {
     43       SyncVar *tmp = tab_[i].val;
     44       tab_[i].val = tmp->next;
     45       DestroyAndFree(tmp);
     46     }
     47   }
     48 }
     49 
     50 SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
     51                              uptr addr, bool write_lock) {
     52 #ifndef TSAN_GO
     53   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
     54     MBlock *b = user_mblock(thr, (void*)addr);
     55     Lock l(&b->mtx);
     56     SyncVar *res = 0;
     57     for (res = b->head; res; res = res->next) {
     58       if (res->addr == addr)
     59         break;
     60     }
     61     if (res == 0) {
     62       StatInc(thr, StatSyncCreated);
     63       void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
     64       res = new(mem) SyncVar(addr);
     65       res->creation_stack.ObtainCurrent(thr, pc);
     66       res->next = b->head;
     67       b->head = res;
     68     }
     69     if (write_lock)
     70       res->mtx.Lock();
     71     else
     72       res->mtx.ReadLock();
     73     return res;
     74   }
     75 #endif
     76 
     77   Part *p = &tab_[PartIdx(addr)];
     78   {
     79     ReadLock l(&p->mtx);
     80     for (SyncVar *res = p->val; res; res = res->next) {
     81       if (res->addr == addr) {
     82         if (write_lock)
     83           res->mtx.Lock();
     84         else
     85           res->mtx.ReadLock();
     86         return res;
     87       }
     88     }
     89   }
     90   {
     91     Lock l(&p->mtx);
     92     SyncVar *res = p->val;
     93     for (; res; res = res->next) {
     94       if (res->addr == addr)
     95         break;
     96     }
     97     if (res == 0) {
     98       StatInc(thr, StatSyncCreated);
     99       void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
    100       res = new(mem) SyncVar(addr);
    101 #ifndef TSAN_GO
    102       res->creation_stack.ObtainCurrent(thr, pc);
    103 #endif
    104       res->next = p->val;
    105       p->val = res;
    106     }
    107     if (write_lock)
    108       res->mtx.Lock();
    109     else
    110       res->mtx.ReadLock();
    111     return res;
    112   }
    113 }
    114 
    115 SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
    116 #ifndef TSAN_GO
    117   if (PrimaryAllocator::PointerIsMine((void*)addr)) {
    118     MBlock *b = user_mblock(thr, (void*)addr);
    119     SyncVar *res = 0;
    120     {
    121       Lock l(&b->mtx);
    122       SyncVar **prev = &b->head;
    123       res = *prev;
    124       while (res) {
    125         if (res->addr == addr) {
    126           if (res->is_linker_init)
    127             return 0;
    128           *prev = res->next;
    129           break;
    130         }
    131         prev = &res->next;
    132         res = *prev;
    133       }
    134     }
    135     if (res) {
    136       StatInc(thr, StatSyncDestroyed);
    137       res->mtx.Lock();
    138       res->mtx.Unlock();
    139     }
    140     return res;
    141   }
    142 #endif
    143 
    144   Part *p = &tab_[PartIdx(addr)];
    145   SyncVar *res = 0;
    146   {
    147     Lock l(&p->mtx);
    148     SyncVar **prev = &p->val;
    149     res = *prev;
    150     while (res) {
    151       if (res->addr == addr) {
    152         if (res->is_linker_init)
    153           return 0;
    154         *prev = res->next;
    155         break;
    156       }
    157       prev = &res->next;
    158       res = *prev;
    159     }
    160   }
    161   if (res) {
    162     StatInc(thr, StatSyncDestroyed);
    163     res->mtx.Lock();
    164     res->mtx.Unlock();
    165   }
    166   return res;
    167 }
    168 
    169 uptr SyncVar::GetMemoryConsumption() {
    170   return sizeof(*this)
    171       + clock.size() * sizeof(u64)
    172       + read_clock.size() * sizeof(u64)
    173       + creation_stack.Size() * sizeof(uptr);
    174 }
    175 
    176 uptr SyncTab::GetMemoryConsumption(uptr *nsync) {
    177   uptr mem = 0;
    178   for (int i = 0; i < kPartCount; i++) {
    179     Part *p = &tab_[i];
    180     Lock l(&p->mtx);
    181     for (SyncVar *s = p->val; s; s = s->next) {
    182       *nsync += 1;
    183       mem += s->GetMemoryConsumption();
    184     }
    185   }
    186   return mem;
    187 }
    188 
    189 int SyncTab::PartIdx(uptr addr) {
    190   return (addr >> 3) % kPartCount;
    191 }
    192 
    193 StackTrace::StackTrace()
    194     : n_()
    195     , s_()
    196     , c_() {
    197 }
    198 
    199 StackTrace::StackTrace(uptr *buf, uptr cnt)
    200     : n_()
    201     , s_(buf)
    202     , c_(cnt) {
    203   CHECK_NE(buf, 0);
    204   CHECK_NE(cnt, 0);
    205 }
    206 
    207 StackTrace::~StackTrace() {
    208   Reset();
    209 }
    210 
    211 void StackTrace::Reset() {
    212   if (s_ && !c_) {
    213     CHECK_NE(n_, 0);
    214     internal_free(s_);
    215     s_ = 0;
    216   }
    217   n_ = 0;
    218 }
    219 
    220 void StackTrace::Init(const uptr *pcs, uptr cnt) {
    221   Reset();
    222   if (cnt == 0)
    223     return;
    224   if (c_) {
    225     CHECK_NE(s_, 0);
    226     CHECK_LE(cnt, c_);
    227   } else {
    228     s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
    229   }
    230   n_ = cnt;
    231   internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
    232 }
    233 
    234 void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
    235   Reset();
    236   n_ = thr->shadow_stack_pos - thr->shadow_stack;
    237   if (n_ + !!toppc == 0)
    238     return;
    239   uptr start = 0;
    240   if (c_) {
    241     CHECK_NE(s_, 0);
    242     if (n_ + !!toppc > c_) {
    243       start = n_ - c_ + !!toppc;
    244       n_ = c_ - !!toppc;
    245     }
    246   } else {
    247     s_ = (uptr*)internal_alloc(MBlockStackTrace,
    248                                (n_ + !!toppc) * sizeof(s_[0]));
    249   }
    250   for (uptr i = 0; i < n_; i++)
    251     s_[i] = thr->shadow_stack[start + i];
    252   if (toppc) {
    253     s_[n_] = toppc;
    254     n_++;
    255   }
    256 }
    257 
    258 void StackTrace::CopyFrom(const StackTrace& other) {
    259   Reset();
    260   Init(other.Begin(), other.Size());
    261 }
    262 
    263 bool StackTrace::IsEmpty() const {
    264   return n_ == 0;
    265 }
    266 
    267 uptr StackTrace::Size() const {
    268   return n_;
    269 }
    270 
    271 uptr StackTrace::Get(uptr i) const {
    272   CHECK_LT(i, n_);
    273   return s_[i];
    274 }
    275 
    276 const uptr *StackTrace::Begin() const {
    277   return s_;
    278 }
    279 
    280 }  // namespace __tsan
    281