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