Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_rtl_mutex.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 
     14 #include "tsan_rtl.h"
     15 #include "tsan_flags.h"
     16 #include "tsan_sync.h"
     17 #include "tsan_report.h"
     18 #include "tsan_symbolize.h"
     19 #include "tsan_platform.h"
     20 
     21 namespace __tsan {
     22 
     23 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
     24                  bool rw, bool recursive, bool linker_init) {
     25   Context *ctx = CTX();
     26   CHECK_GT(thr->in_rtl, 0);
     27   DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
     28   StatInc(thr, StatMutexCreate);
     29   if (!linker_init && IsAppMem(addr))
     30     MemoryWrite1Byte(thr, pc, addr);
     31   SyncVar *s = ctx->synctab.GetAndLock(thr, pc, addr, true);
     32   s->is_rw = rw;
     33   s->is_recursive = recursive;
     34   s->is_linker_init = linker_init;
     35   s->mtx.Unlock();
     36 }
     37 
     38 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
     39   Context *ctx = CTX();
     40   CHECK_GT(thr->in_rtl, 0);
     41   DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
     42   StatInc(thr, StatMutexDestroy);
     43 #ifndef TSAN_GO
     44   // Global mutexes not marked as LINKER_INITIALIZED
     45   // cause tons of not interesting reports, so just ignore it.
     46   if (IsGlobalVar(addr))
     47     return;
     48 #endif
     49   SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
     50   if (s == 0)
     51     return;
     52   if (IsAppMem(addr))
     53     MemoryWrite1Byte(thr, pc, addr);
     54   if (flags()->report_destroy_locked
     55       && s->owner_tid != SyncVar::kInvalidTid
     56       && !s->is_broken) {
     57     s->is_broken = true;
     58     ScopedReport rep(ReportTypeMutexDestroyLocked);
     59     rep.AddMutex(s);
     60     StackTrace trace;
     61     trace.ObtainCurrent(thr, pc);
     62     rep.AddStack(&trace);
     63     FastState last(s->last_lock);
     64     RestoreStack(last.tid(), last.epoch(), &trace);
     65     rep.AddStack(&trace);
     66     rep.AddLocation(s->addr, 1);
     67     OutputReport(rep);
     68   }
     69   DestroyAndFree(s);
     70 }
     71 
     72 void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
     73   CHECK_GT(thr->in_rtl, 0);
     74   DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
     75   if (IsAppMem(addr))
     76     MemoryRead1Byte(thr, pc, addr);
     77   thr->fast_state.IncrementEpoch();
     78   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeLock, addr);
     79   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
     80   if (s->owner_tid == SyncVar::kInvalidTid) {
     81     CHECK_EQ(s->recursion, 0);
     82     s->owner_tid = thr->tid;
     83     s->last_lock = thr->fast_state.raw();
     84   } else if (s->owner_tid == thr->tid) {
     85     CHECK_GT(s->recursion, 0);
     86   } else {
     87     TsanPrintf("ThreadSanitizer WARNING: double lock\n");
     88     PrintCurrentStack(thr, pc);
     89   }
     90   if (s->recursion == 0) {
     91     StatInc(thr, StatMutexLock);
     92     thr->clock.set(thr->tid, thr->fast_state.epoch());
     93     thr->clock.acquire(&s->clock);
     94     StatInc(thr, StatSyncAcquire);
     95     thr->clock.acquire(&s->read_clock);
     96     StatInc(thr, StatSyncAcquire);
     97   } else if (!s->is_recursive) {
     98     StatInc(thr, StatMutexRecLock);
     99   }
    100   s->recursion++;
    101   s->mtx.Unlock();
    102 }
    103 
    104 void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
    105   CHECK_GT(thr->in_rtl, 0);
    106   DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
    107   if (IsAppMem(addr))
    108     MemoryRead1Byte(thr, pc, addr);
    109   thr->fast_state.IncrementEpoch();
    110   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeUnlock, addr);
    111   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
    112   if (s->recursion == 0) {
    113     if (!s->is_broken) {
    114       s->is_broken = true;
    115       TsanPrintf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
    116       PrintCurrentStack(thr, pc);
    117     }
    118   } else if (s->owner_tid != thr->tid) {
    119     if (!s->is_broken) {
    120       s->is_broken = true;
    121       TsanPrintf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
    122       PrintCurrentStack(thr, pc);
    123     }
    124   } else {
    125     s->recursion--;
    126     if (s->recursion == 0) {
    127       StatInc(thr, StatMutexUnlock);
    128       s->owner_tid = SyncVar::kInvalidTid;
    129       thr->clock.set(thr->tid, thr->fast_state.epoch());
    130       thr->fast_synch_epoch = thr->fast_state.epoch();
    131       thr->clock.ReleaseStore(&s->clock);
    132       StatInc(thr, StatSyncRelease);
    133     } else {
    134       StatInc(thr, StatMutexRecUnlock);
    135     }
    136   }
    137   s->mtx.Unlock();
    138 }
    139 
    140 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
    141   CHECK_GT(thr->in_rtl, 0);
    142   DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
    143   StatInc(thr, StatMutexReadLock);
    144   if (IsAppMem(addr))
    145     MemoryRead1Byte(thr, pc, addr);
    146   thr->fast_state.IncrementEpoch();
    147   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeRLock, addr);
    148   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, false);
    149   if (s->owner_tid != SyncVar::kInvalidTid) {
    150     TsanPrintf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
    151     PrintCurrentStack(thr, pc);
    152   }
    153   thr->clock.set(thr->tid, thr->fast_state.epoch());
    154   thr->clock.acquire(&s->clock);
    155   s->last_lock = thr->fast_state.raw();
    156   StatInc(thr, StatSyncAcquire);
    157   s->mtx.ReadUnlock();
    158 }
    159 
    160 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
    161   CHECK_GT(thr->in_rtl, 0);
    162   DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
    163   StatInc(thr, StatMutexReadUnlock);
    164   if (IsAppMem(addr))
    165     MemoryRead1Byte(thr, pc, addr);
    166   thr->fast_state.IncrementEpoch();
    167   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeRUnlock, addr);
    168   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
    169   if (s->owner_tid != SyncVar::kInvalidTid) {
    170     TsanPrintf("ThreadSanitizer WARNING: read unlock of a write "
    171                "locked mutex\n");
    172     PrintCurrentStack(thr, pc);
    173   }
    174   thr->clock.set(thr->tid, thr->fast_state.epoch());
    175   thr->fast_synch_epoch = thr->fast_state.epoch();
    176   thr->clock.release(&s->read_clock);
    177   StatInc(thr, StatSyncRelease);
    178   s->mtx.Unlock();
    179 }
    180 
    181 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
    182   CHECK_GT(thr->in_rtl, 0);
    183   DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
    184   if (IsAppMem(addr))
    185     MemoryRead1Byte(thr, pc, addr);
    186   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
    187   if (s->owner_tid == SyncVar::kInvalidTid) {
    188     // Seems to be read unlock.
    189     StatInc(thr, StatMutexReadUnlock);
    190     thr->fast_state.IncrementEpoch();
    191     TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeRUnlock, addr);
    192     thr->clock.set(thr->tid, thr->fast_state.epoch());
    193     thr->fast_synch_epoch = thr->fast_state.epoch();
    194     thr->clock.release(&s->read_clock);
    195     StatInc(thr, StatSyncRelease);
    196   } else if (s->owner_tid == thr->tid) {
    197     // Seems to be write unlock.
    198     CHECK_GT(s->recursion, 0);
    199     s->recursion--;
    200     if (s->recursion == 0) {
    201       StatInc(thr, StatMutexUnlock);
    202       s->owner_tid = SyncVar::kInvalidTid;
    203       // FIXME: Refactor me, plz.
    204       // The sequence of events is quite tricky and doubled in several places.
    205       // First, it's a bug to increment the epoch w/o writing to the trace.
    206       // Then, the acquire/release logic can be factored out as well.
    207       thr->fast_state.IncrementEpoch();
    208       TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeUnlock, addr);
    209       thr->clock.set(thr->tid, thr->fast_state.epoch());
    210       thr->fast_synch_epoch = thr->fast_state.epoch();
    211       thr->clock.ReleaseStore(&s->clock);
    212       StatInc(thr, StatSyncRelease);
    213     } else {
    214       StatInc(thr, StatMutexRecUnlock);
    215     }
    216   } else if (!s->is_broken) {
    217     s->is_broken = true;
    218     TsanPrintf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
    219     PrintCurrentStack(thr, pc);
    220   }
    221   s->mtx.Unlock();
    222 }
    223 
    224 void Acquire(ThreadState *thr, uptr pc, uptr addr) {
    225   CHECK_GT(thr->in_rtl, 0);
    226   DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
    227   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, false);
    228   thr->clock.set(thr->tid, thr->fast_state.epoch());
    229   thr->clock.acquire(&s->clock);
    230   StatInc(thr, StatSyncAcquire);
    231   s->mtx.ReadUnlock();
    232 }
    233 
    234 void Release(ThreadState *thr, uptr pc, uptr addr) {
    235   CHECK_GT(thr->in_rtl, 0);
    236   DPrintf("#%d: Release %zx\n", thr->tid, addr);
    237   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
    238   thr->clock.set(thr->tid, thr->fast_state.epoch());
    239   thr->clock.release(&s->clock);
    240   StatInc(thr, StatSyncRelease);
    241   s->mtx.Unlock();
    242 }
    243 
    244 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
    245   CHECK_GT(thr->in_rtl, 0);
    246   DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
    247   SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
    248   thr->clock.set(thr->tid, thr->fast_state.epoch());
    249   thr->clock.ReleaseStore(&s->clock);
    250   StatInc(thr, StatSyncRelease);
    251   s->mtx.Unlock();
    252 }
    253 
    254 #ifndef TSAN_GO
    255 void AfterSleep(ThreadState *thr, uptr pc) {
    256   Context *ctx = CTX();
    257   thr->last_sleep_stack_id = CurrentStackId(thr, pc);
    258   Lock l(&ctx->thread_mtx);
    259   for (unsigned i = 0; i < kMaxTid; i++) {
    260     ThreadContext *tctx = ctx->threads[i];
    261     if (tctx == 0)
    262       continue;
    263     if (tctx->status == ThreadStatusRunning)
    264       thr->last_sleep_clock.set(i, tctx->thr->fast_state.epoch());
    265     else
    266       thr->last_sleep_clock.set(i, tctx->epoch1);
    267   }
    268 }
    269 #endif
    270 
    271 }  // namespace __tsan
    272