tsan_sync.cc revision 9ad7c32720dfa1287f8cfd481e5d583435178cae
1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_sync.cc ------------------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
1347b1634df012507799eb39aa17d4022d748ba67bAlexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h"
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_sync.h"
157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h"
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
207ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncVar::SyncVar(uptr addr)
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : mtx(MutexTypeSyncVar, StatMtxSyncVar)
227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , addr(addr)
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , owner_tid(kInvalidTid)
247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , recursion()
257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , is_rw()
267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , is_recursive()
277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , is_broken() {
287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
307ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::Part::Part()
317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : mtx(MutexTypeSyncTab, StatMtxSyncTab)
327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , val() {
337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
357ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::SyncTab() {
367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
387ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::~SyncTab() {
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; i < kPartCount; i++) {
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (tab_[i].val) {
417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      SyncVar *tmp = tab_[i].val;
427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      tab_[i].val = tmp->next;
437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      DestroyAndFree(tmp);
447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
487ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany                             uptr addr, bool write_lock) {
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Part *p = &tab_[PartIdx(addr)];
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ReadLock l(&p->mtx);
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (SyncVar *res = p->val; res; res = res->next) {
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr) {
557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        if (write_lock)
567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          res->mtx.Lock();
577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        else
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          res->mtx.ReadLock();
597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        return res;
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Lock l(&p->mtx);
657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    SyncVar *res = p->val;
667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (; res; res = res->next) {
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr)
687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (res == 0) {
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      StatInc(thr, StatSyncCreated);
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res = new(mem) SyncVar(addr);
747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->creation_stack.ObtainCurrent(thr, pc);
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->next = p->val;
767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      p->val = res;
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (write_lock)
797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->mtx.Lock();
807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->mtx.ReadLock();
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return res;
837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
867ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Part *p = &tab_[PartIdx(addr)];
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  SyncVar *res = 0;
897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Lock l(&p->mtx);
917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    SyncVar **prev = &p->val;
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res = *prev;
937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (res) {
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr) {
957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        *prev = res->next;
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      prev = &res->next;
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res = *prev;
1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (res) {
1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    StatInc(thr, StatSyncDestroyed);
1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res->mtx.Lock();
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res->mtx.Unlock();
1067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return res;
1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
11026127735454fddae3495794f38189d57dde6510fDmitry Vyukovuptr SyncVar::GetMemoryConsumption() {
11126127735454fddae3495794f38189d57dde6510fDmitry Vyukov  return sizeof(*this)
11226127735454fddae3495794f38189d57dde6510fDmitry Vyukov      + clock.size() * sizeof(u64)
11326127735454fddae3495794f38189d57dde6510fDmitry Vyukov      + read_clock.size() * sizeof(u64)
11426127735454fddae3495794f38189d57dde6510fDmitry Vyukov      + creation_stack.Size() * sizeof(uptr);
11526127735454fddae3495794f38189d57dde6510fDmitry Vyukov}
11626127735454fddae3495794f38189d57dde6510fDmitry Vyukov
11726127735454fddae3495794f38189d57dde6510fDmitry Vyukovuptr SyncTab::GetMemoryConsumption(uptr *nsync) {
11826127735454fddae3495794f38189d57dde6510fDmitry Vyukov  uptr mem = 0;
11926127735454fddae3495794f38189d57dde6510fDmitry Vyukov  for (int i = 0; i < kPartCount; i++) {
12026127735454fddae3495794f38189d57dde6510fDmitry Vyukov    Part *p = &tab_[i];
12126127735454fddae3495794f38189d57dde6510fDmitry Vyukov    Lock l(&p->mtx);
12226127735454fddae3495794f38189d57dde6510fDmitry Vyukov    for (SyncVar *s = p->val; s; s = s->next) {
12326127735454fddae3495794f38189d57dde6510fDmitry Vyukov      *nsync += 1;
12426127735454fddae3495794f38189d57dde6510fDmitry Vyukov      mem += s->GetMemoryConsumption();
12526127735454fddae3495794f38189d57dde6510fDmitry Vyukov    }
12626127735454fddae3495794f38189d57dde6510fDmitry Vyukov  }
12726127735454fddae3495794f38189d57dde6510fDmitry Vyukov  return mem;
12826127735454fddae3495794f38189d57dde6510fDmitry Vyukov}
12926127735454fddae3495794f38189d57dde6510fDmitry Vyukov
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyint SyncTab::PartIdx(uptr addr) {
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return (addr >> 3) % kPartCount;
1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1347ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyStackTrace::StackTrace()
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : n_()
1369ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , s_()
1379ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , c_() {
1389ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov}
1399ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov
1409ad7c32720dfa1287f8cfd481e5d583435178caeDmitry VyukovStackTrace::StackTrace(uptr *buf, uptr cnt)
1419ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    : n_()
1429ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , s_(buf)
1439ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , c_(cnt) {
1449ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  CHECK_NE(buf, 0);
1459ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  CHECK_NE(cnt, 0);
1467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1487ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyStackTrace::~StackTrace() {
1497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::Reset() {
1539ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (s_ && !c_) {
1547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK_NE(n_, 0);
1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    internal_free(s_);
1567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    s_ = 0;
1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1589ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  n_ = 0;
1597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::Init(const uptr *pcs, uptr cnt) {
1627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
1637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (cnt == 0)
1647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
1659ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (c_) {
1669ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_NE(s_, 0);
1679ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_LE(cnt, c_);
1689ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  } else {
1699ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
1709ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  }
1717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  n_ = cnt;
1729ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
1737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
1777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  n_ = thr->shadow_stack_pos - &thr->shadow_stack[0];
1787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (n_ + !!toppc == 0)
1797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
1809ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (c_) {
1819ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_NE(s_, 0);
1829ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_LE(n_ + !!toppc, c_);
1839ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  } else {
1849ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    s_ = (uptr*)internal_alloc(MBlockStackTrace,
1859ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov                               (n_ + !!toppc) * sizeof(s_[0]));
1869ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  }
1877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < n_; i++)
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    s_[i] = thr->shadow_stack[i];
1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (toppc) {
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    s_[n_] = toppc;
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    n_++;
1927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::CopyFrom(const StackTrace& other) {
1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
1977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Init(other.Begin(), other.Size());
1987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool StackTrace::IsEmpty() const {
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return n_ == 0;
2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyuptr StackTrace::Size() const {
2057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return n_;
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyuptr StackTrace::Get(uptr i) const {
2097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CHECK_LT(i, n_);
2107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return s_[i];
2117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst uptr *StackTrace::Begin() const {
2147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return s_;
2157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
218