Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_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 #include "sanitizer_common/sanitizer_libc.h"
     14 #include "tsan_mutex.h"
     15 #include "tsan_platform.h"
     16 #include "tsan_rtl.h"
     17 
     18 namespace __tsan {
     19 
     20 // Simple reader-writer spin-mutex. Optimized for not-so-contended case.
     21 // Readers have preference, can possibly starvate writers.
     22 
     23 // The table fixes what mutexes can be locked under what mutexes.
     24 // E.g. if the row for MutexTypeThreads contains MutexTypeReport,
     25 // then Report mutex can be locked while under Threads mutex.
     26 // The leaf mutexes can be locked under any other mutexes.
     27 // Recursive locking is not supported.
     28 #if SANITIZER_DEBUG && !SANITIZER_GO
     29 const MutexType MutexTypeLeaf = (MutexType)-1;
     30 static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
     31   /*0  MutexTypeInvalid*/     {},
     32   /*1  MutexTypeTrace*/       {MutexTypeLeaf},
     33   /*2  MutexTypeThreads*/     {MutexTypeReport},
     34   /*3  MutexTypeReport*/      {MutexTypeSyncVar,
     35                                MutexTypeMBlock, MutexTypeJavaMBlock},
     36   /*4  MutexTypeSyncVar*/     {MutexTypeDDetector},
     37   /*5  MutexTypeSyncTab*/     {},  // unused
     38   /*6  MutexTypeSlab*/        {MutexTypeLeaf},
     39   /*7  MutexTypeAnnotations*/ {},
     40   /*8  MutexTypeAtExit*/      {MutexTypeSyncVar},
     41   /*9  MutexTypeMBlock*/      {MutexTypeSyncVar},
     42   /*10 MutexTypeJavaMBlock*/  {MutexTypeSyncVar},
     43   /*11 MutexTypeDDetector*/   {},
     44   /*12 MutexTypeFired*/       {MutexTypeLeaf},
     45   /*13 MutexTypeRacy*/        {MutexTypeLeaf},
     46   /*14 MutexTypeGlobalProc*/  {},
     47 };
     48 
     49 static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
     50 #endif
     51 
     52 void InitializeMutex() {
     53 #if SANITIZER_DEBUG && !SANITIZER_GO
     54   // Build the "can lock" adjacency matrix.
     55   // If [i][j]==true, then one can lock mutex j while under mutex i.
     56   const int N = MutexTypeCount;
     57   int cnt[N] = {};
     58   bool leaf[N] = {};
     59   for (int i = 1; i < N; i++) {
     60     for (int j = 0; j < N; j++) {
     61       MutexType z = CanLockTab[i][j];
     62       if (z == MutexTypeInvalid)
     63         continue;
     64       if (z == MutexTypeLeaf) {
     65         CHECK(!leaf[i]);
     66         leaf[i] = true;
     67         continue;
     68       }
     69       CHECK(!CanLockAdj[i][(int)z]);
     70       CanLockAdj[i][(int)z] = true;
     71       cnt[i]++;
     72     }
     73   }
     74   for (int i = 0; i < N; i++) {
     75     CHECK(!leaf[i] || cnt[i] == 0);
     76   }
     77   // Add leaf mutexes.
     78   for (int i = 0; i < N; i++) {
     79     if (!leaf[i])
     80       continue;
     81     for (int j = 0; j < N; j++) {
     82       if (i == j || leaf[j] || j == MutexTypeInvalid)
     83         continue;
     84       CHECK(!CanLockAdj[j][i]);
     85       CanLockAdj[j][i] = true;
     86     }
     87   }
     88   // Build the transitive closure.
     89   bool CanLockAdj2[MutexTypeCount][MutexTypeCount];
     90   for (int i = 0; i < N; i++) {
     91     for (int j = 0; j < N; j++) {
     92       CanLockAdj2[i][j] = CanLockAdj[i][j];
     93     }
     94   }
     95   for (int k = 0; k < N; k++) {
     96     for (int i = 0; i < N; i++) {
     97       for (int j = 0; j < N; j++) {
     98         if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) {
     99           CanLockAdj2[i][j] = true;
    100         }
    101       }
    102     }
    103   }
    104 #if 0
    105   Printf("Can lock graph:\n");
    106   for (int i = 0; i < N; i++) {
    107     for (int j = 0; j < N; j++) {
    108       Printf("%d ", CanLockAdj[i][j]);
    109     }
    110     Printf("\n");
    111   }
    112   Printf("Can lock graph closure:\n");
    113   for (int i = 0; i < N; i++) {
    114     for (int j = 0; j < N; j++) {
    115       Printf("%d ", CanLockAdj2[i][j]);
    116     }
    117     Printf("\n");
    118   }
    119 #endif
    120   // Verify that the graph is acyclic.
    121   for (int i = 0; i < N; i++) {
    122     if (CanLockAdj2[i][i]) {
    123       Printf("Mutex %d participates in a cycle\n", i);
    124       Die();
    125     }
    126   }
    127 #endif
    128 }
    129 
    130 InternalDeadlockDetector::InternalDeadlockDetector() {
    131   // Rely on zero initialization because some mutexes can be locked before ctor.
    132 }
    133 
    134 #if SANITIZER_DEBUG && !SANITIZER_GO
    135 void InternalDeadlockDetector::Lock(MutexType t) {
    136   // Printf("LOCK %d @%zu\n", t, seq_ + 1);
    137   CHECK_GT(t, MutexTypeInvalid);
    138   CHECK_LT(t, MutexTypeCount);
    139   u64 max_seq = 0;
    140   u64 max_idx = MutexTypeInvalid;
    141   for (int i = 0; i != MutexTypeCount; i++) {
    142     if (locked_[i] == 0)
    143       continue;
    144     CHECK_NE(locked_[i], max_seq);
    145     if (max_seq < locked_[i]) {
    146       max_seq = locked_[i];
    147       max_idx = i;
    148     }
    149   }
    150   locked_[t] = ++seq_;
    151   if (max_idx == MutexTypeInvalid)
    152     return;
    153   // Printf("  last %d @%zu\n", max_idx, max_seq);
    154   if (!CanLockAdj[max_idx][t]) {
    155     Printf("ThreadSanitizer: internal deadlock detected\n");
    156     Printf("ThreadSanitizer: can't lock %d while under %zu\n",
    157                t, (uptr)max_idx);
    158     CHECK(0);
    159   }
    160 }
    161 
    162 void InternalDeadlockDetector::Unlock(MutexType t) {
    163   // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
    164   CHECK(locked_[t]);
    165   locked_[t] = 0;
    166 }
    167 
    168 void InternalDeadlockDetector::CheckNoLocks() {
    169   for (int i = 0; i != MutexTypeCount; i++) {
    170     CHECK_EQ(locked_[i], 0);
    171   }
    172 }
    173 #endif
    174 
    175 void CheckNoLocks(ThreadState *thr) {
    176 #if SANITIZER_DEBUG && !SANITIZER_GO
    177   thr->internal_deadlock_detector.CheckNoLocks();
    178 #endif
    179 }
    180 
    181 const uptr kUnlocked = 0;
    182 const uptr kWriteLock = 1;
    183 const uptr kReadLock = 2;
    184 
    185 class Backoff {
    186  public:
    187   Backoff()
    188     : iter_() {
    189   }
    190 
    191   bool Do() {
    192     if (iter_++ < kActiveSpinIters)
    193       proc_yield(kActiveSpinCnt);
    194     else
    195       internal_sched_yield();
    196     return true;
    197   }
    198 
    199   u64 Contention() const {
    200     u64 active = iter_ % kActiveSpinIters;
    201     u64 passive = iter_ - active;
    202     return active + 10 * passive;
    203   }
    204 
    205  private:
    206   int iter_;
    207   static const int kActiveSpinIters = 10;
    208   static const int kActiveSpinCnt = 20;
    209 };
    210 
    211 Mutex::Mutex(MutexType type, StatType stat_type) {
    212   CHECK_GT(type, MutexTypeInvalid);
    213   CHECK_LT(type, MutexTypeCount);
    214 #if SANITIZER_DEBUG
    215   type_ = type;
    216 #endif
    217 #if TSAN_COLLECT_STATS
    218   stat_type_ = stat_type;
    219 #endif
    220   atomic_store(&state_, kUnlocked, memory_order_relaxed);
    221 }
    222 
    223 Mutex::~Mutex() {
    224   CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
    225 }
    226 
    227 void Mutex::Lock() {
    228 #if SANITIZER_DEBUG && !SANITIZER_GO
    229   cur_thread()->internal_deadlock_detector.Lock(type_);
    230 #endif
    231   uptr cmp = kUnlocked;
    232   if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
    233                                      memory_order_acquire))
    234     return;
    235   for (Backoff backoff; backoff.Do();) {
    236     if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) {
    237       cmp = kUnlocked;
    238       if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
    239                                        memory_order_acquire)) {
    240 #if TSAN_COLLECT_STATS && !SANITIZER_GO
    241         StatInc(cur_thread(), stat_type_, backoff.Contention());
    242 #endif
    243         return;
    244       }
    245     }
    246   }
    247 }
    248 
    249 void Mutex::Unlock() {
    250   uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
    251   (void)prev;
    252   DCHECK_NE(prev & kWriteLock, 0);
    253 #if SANITIZER_DEBUG && !SANITIZER_GO
    254   cur_thread()->internal_deadlock_detector.Unlock(type_);
    255 #endif
    256 }
    257 
    258 void Mutex::ReadLock() {
    259 #if SANITIZER_DEBUG && !SANITIZER_GO
    260   cur_thread()->internal_deadlock_detector.Lock(type_);
    261 #endif
    262   uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
    263   if ((prev & kWriteLock) == 0)
    264     return;
    265   for (Backoff backoff; backoff.Do();) {
    266     prev = atomic_load(&state_, memory_order_acquire);
    267     if ((prev & kWriteLock) == 0) {
    268 #if TSAN_COLLECT_STATS && !SANITIZER_GO
    269       StatInc(cur_thread(), stat_type_, backoff.Contention());
    270 #endif
    271       return;
    272     }
    273   }
    274 }
    275 
    276 void Mutex::ReadUnlock() {
    277   uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
    278   (void)prev;
    279   DCHECK_EQ(prev & kWriteLock, 0);
    280   DCHECK_GT(prev & ~kWriteLock, 0);
    281 #if SANITIZER_DEBUG && !SANITIZER_GO
    282   cur_thread()->internal_deadlock_detector.Unlock(type_);
    283 #endif
    284 }
    285 
    286 void Mutex::CheckLocked() {
    287   CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0);
    288 }
    289 
    290 }  // namespace __tsan
    291