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:
TestData(MutexType * mtx)25   explicit TestData(MutexType *mtx)
26     : mtx_(mtx) {
27     for (int i = 0; i < kSize; i++)
28       data_[i] = 0;
29   }
30 
Write()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 
Read()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 
Backoff()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 SANITIZER_DEBUG
68 const int kIters = 16*1024;
69 #else
70 const int kIters = 64*1024;
71 #endif
72 
73 template<typename MutexType>
write_mutex_thread(void * param)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>
read_mutex_thread(void * param)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 
TEST(Mutex,Write)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 
TEST(Mutex,ReadWrite)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 
TEST(Mutex,SpinWrite)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