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
20namespace __tsan {
21
22template<typename MutexType>
23class 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
65const int kThreads = 8;
66const int kWriteRate = 1024;
67#if SANITIZER_DEBUG
68const int kIters = 16*1024;
69#else
70const int kIters = 64*1024;
71#endif
72
73template<typename MutexType>
74static 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
83template<typename MutexType>
84static 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
96TEST(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
106TEST(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
116TEST(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