sanitizer_mutex_test.cc revision a09507c38cf9dd9119e5aa9bd6d91383514f857b
1//===-- sanitizer_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/AddressSanitizer runtime.
11//
12//===----------------------------------------------------------------------===//
13#include "sanitizer_common/sanitizer_mutex.h"
14#include "sanitizer_common/sanitizer_common.h"
15#include "gtest/gtest.h"
16
17#include <string.h>
18
19namespace __sanitizer {
20
21template<typename MutexType>
22class TestData {
23 public:
24  explicit TestData(MutexType *mtx)
25      : mtx_(mtx) {
26    for (int i = 0; i < kSize; i++)
27      data_[i] = 0;
28  }
29
30  void Write() {
31    Lock l(mtx_);
32    T v0 = data_[0];
33    for (int i = 0; i < kSize; i++) {
34      CHECK_EQ(data_[i], v0);
35      data_[i]++;
36    }
37  }
38
39  void TryWrite() {
40    if (!mtx_->TryLock())
41      return;
42    T v0 = data_[0];
43    for (int i = 0; i < kSize; i++) {
44      CHECK_EQ(data_[i], v0);
45      data_[i]++;
46    }
47    mtx_->Unlock();
48  }
49
50  void Backoff() {
51    volatile T data[kSize] = {};
52    for (int i = 0; i < kSize; i++) {
53      data[i]++;
54      CHECK_EQ(data[i], 1);
55    }
56  }
57
58 private:
59  typedef GenericScopedLock<MutexType> Lock;
60  static const int kSize = 64;
61  typedef u64 T;
62  MutexType *mtx_;
63  char pad_[kCacheLineSize];
64  T data_[kSize];
65};
66
67const int kThreads = 8;
68#if SANITIZER_DEBUG
69const int kIters = 16*1024;
70#else
71const int kIters = 64*1024;
72#endif
73
74template<typename MutexType>
75static void *lock_thread(void *param) {
76  TestData<MutexType> *data = (TestData<MutexType>*)param;
77  for (int i = 0; i < kIters; i++) {
78    data->Write();
79    data->Backoff();
80  }
81  return 0;
82}
83
84template<typename MutexType>
85static void *try_thread(void *param) {
86  TestData<MutexType> *data = (TestData<MutexType>*)param;
87  for (int i = 0; i < kIters; i++) {
88    data->TryWrite();
89    data->Backoff();
90  }
91  return 0;
92}
93
94template<typename MutexType>
95static void check_locked(MutexType *mtx) {
96  GenericScopedLock<MutexType> l(mtx);
97  mtx->CheckLocked();
98}
99
100TEST(SanitizerCommon, SpinMutex) {
101  SpinMutex mtx;
102  mtx.Init();
103  TestData<SpinMutex> data(&mtx);
104  pthread_t threads[kThreads];
105  for (int i = 0; i < kThreads; i++)
106    pthread_create(&threads[i], 0, lock_thread<SpinMutex>, &data);
107  for (int i = 0; i < kThreads; i++)
108    pthread_join(threads[i], 0);
109}
110
111TEST(SanitizerCommon, SpinMutexTry) {
112  SpinMutex mtx;
113  mtx.Init();
114  TestData<SpinMutex> data(&mtx);
115  pthread_t threads[kThreads];
116  for (int i = 0; i < kThreads; i++)
117    pthread_create(&threads[i], 0, try_thread<SpinMutex>, &data);
118  for (int i = 0; i < kThreads; i++)
119    pthread_join(threads[i], 0);
120}
121
122TEST(SanitizerCommon, BlockingMutex) {
123  u64 mtxmem[1024] = {};
124  BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED);
125  TestData<BlockingMutex> data(mtx);
126  pthread_t threads[kThreads];
127  for (int i = 0; i < kThreads; i++)
128    pthread_create(&threads[i], 0, lock_thread<BlockingMutex>, &data);
129  for (int i = 0; i < kThreads; i++)
130    pthread_join(threads[i], 0);
131  check_locked(mtx);
132}
133
134}  // namespace __sanitizer
135