Home | History | Annotate | Download | only in unit
      1 //===-- tsan_mutex_test.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_internal_defs.h"
     14 #include "sanitizer_common/sanitizer_atomic.h"
     15 #include "sanitizer_common/sanitizer_common.h"
     16 #include "sanitizer_common/sanitizer_mutex.h"
     17 #include "tsan_mutex.h"
     18 #include "gtest/gtest.h"
     19 
     20 namespace __tsan {
     21 
     22 template<typename MutexType>
     23 class TestData {
     24  public:
     25   explicit TestData(MutexType *mtx)
     26     : mtx_(mtx) {
     27     for (int i = 0; i < kSize; i++)
     28       data_[i] = 0;
     29   }
     30 
     31   void Write() {
     32     Lock l(mtx_);
     33     T v0 = data_[0];
     34     for (int i = 0; i < kSize; i++) {
     35       CHECK_EQ(data_[i], v0);
     36       data_[i]++;
     37     }
     38   }
     39 
     40   void Read() {
     41     ReadLock l(mtx_);
     42     T v0 = data_[0];
     43     for (int i = 0; i < kSize; i++) {
     44       CHECK_EQ(data_[i], v0);
     45     }
     46   }
     47 
     48   void Backoff() {
     49     volatile T data[kSize] = {};
     50     for (int i = 0; i < kSize; i++) {
     51       data[i]++;
     52       CHECK_EQ(data[i], 1);
     53     }
     54   }
     55 
     56  private:
     57   typedef GenericScopedLock<MutexType> Lock;
     58   static const int kSize = 64;
     59   typedef u64 T;
     60   MutexType *mtx_;
     61   char pad_[kCacheLineSize];
     62   T data_[kSize];
     63 };
     64 
     65 const int kThreads = 8;
     66 const int kWriteRate = 1024;
     67 #if TSAN_DEBUG
     68 const int kIters = 16*1024;
     69 #else
     70 const int kIters = 64*1024;
     71 #endif
     72 
     73 template<typename MutexType>
     74 static void *write_mutex_thread(void *param) {
     75   TestData<MutexType> *data = (TestData<MutexType>*)param;
     76   for (int i = 0; i < kIters; i++) {
     77     data->Write();
     78     data->Backoff();
     79   }
     80   return 0;
     81 }
     82 
     83 template<typename MutexType>
     84 static void *read_mutex_thread(void *param) {
     85   TestData<MutexType> *data = (TestData<MutexType>*)param;
     86   for (int i = 0; i < kIters; i++) {
     87     if ((i % kWriteRate) == 0)
     88       data->Write();
     89     else
     90       data->Read();
     91     data->Backoff();
     92   }
     93   return 0;
     94 }
     95 
     96 TEST(Mutex, Write) {
     97   Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
     98   TestData<Mutex> data(&mtx);
     99   pthread_t threads[kThreads];
    100   for (int i = 0; i < kThreads; i++)
    101     pthread_create(&threads[i], 0, write_mutex_thread<Mutex>, &data);
    102   for (int i = 0; i < kThreads; i++)
    103     pthread_join(threads[i], 0);
    104 }
    105 
    106 TEST(Mutex, ReadWrite) {
    107   Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations);
    108   TestData<Mutex> data(&mtx);
    109   pthread_t threads[kThreads];
    110   for (int i = 0; i < kThreads; i++)
    111     pthread_create(&threads[i], 0, read_mutex_thread<Mutex>, &data);
    112   for (int i = 0; i < kThreads; i++)
    113     pthread_join(threads[i], 0);
    114 }
    115 
    116 TEST(Mutex, SpinWrite) {
    117   SpinMutex mtx;
    118   TestData<SpinMutex> data(&mtx);
    119   pthread_t threads[kThreads];
    120   for (int i = 0; i < kThreads; i++)
    121     pthread_create(&threads[i], 0, write_mutex_thread<SpinMutex>, &data);
    122   for (int i = 0; i < kThreads; i++)
    123     pthread_join(threads[i], 0);
    124 }
    125 
    126 }  // namespace __tsan
    127