131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//===-- sanitizer_mutex_test.cc -------------------------------------------===//
231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//
331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//                     The LLVM Compiler Infrastructure
431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//
531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov// This file is distributed under the University of Illinois Open Source
631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov// License. See LICENSE.TXT for details.
731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//
831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//===----------------------------------------------------------------------===//
931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//
1031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
1131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//
1231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov//===----------------------------------------------------------------------===//
1331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#include "sanitizer_common/sanitizer_mutex.h"
1431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#include "sanitizer_common/sanitizer_common.h"
152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_pthread_wrappers.h"
172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#include "gtest/gtest.h"
1931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
2031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#include <string.h>
2131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
2231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovnamespace __sanitizer {
2331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
2431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovtemplate<typename MutexType>
2531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovclass TestData {
2631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov public:
2731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  explicit TestData(MutexType *mtx)
2831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      : mtx_(mtx) {
2931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    for (int i = 0; i < kSize; i++)
3031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      data_[i] = 0;
3131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
3231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
3331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  void Write() {
3431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    Lock l(mtx_);
3531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    T v0 = data_[0];
3631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    for (int i = 0; i < kSize; i++) {
3731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      CHECK_EQ(data_[i], v0);
3831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      data_[i]++;
3931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    }
4031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
4131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
4231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  void TryWrite() {
4331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    if (!mtx_->TryLock())
4431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      return;
4531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    T v0 = data_[0];
4631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    for (int i = 0; i < kSize; i++) {
4731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      CHECK_EQ(data_[i], v0);
4831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      data_[i]++;
4931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    }
5031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    mtx_->Unlock();
5131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
5231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
5331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  void Backoff() {
5431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    volatile T data[kSize] = {};
5531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    for (int i = 0; i < kSize; i++) {
5631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      data[i]++;
5731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov      CHECK_EQ(data[i], 1);
5831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    }
5931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
6031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
6131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov private:
6231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  typedef GenericScopedLock<MutexType> Lock;
6331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  static const int kSize = 64;
6431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  typedef u64 T;
6531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  MutexType *mtx_;
6631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  char pad_[kCacheLineSize];
6731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  T data_[kSize];
6831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov};
6931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
7031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovconst int kThreads = 8;
7131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#if SANITIZER_DEBUG
7231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovconst int kIters = 16*1024;
7331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#else
7431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovconst int kIters = 64*1024;
7531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov#endif
7631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
7731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovtemplate<typename MutexType>
7831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovstatic void *lock_thread(void *param) {
7931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  TestData<MutexType> *data = (TestData<MutexType>*)param;
8031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kIters; i++) {
8131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    data->Write();
8231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    data->Backoff();
8331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
8431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  return 0;
8531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}
8631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
8731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovtemplate<typename MutexType>
8831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukovstatic void *try_thread(void *param) {
8931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  TestData<MutexType> *data = (TestData<MutexType>*)param;
9031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kIters; i++) {
9131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    data->TryWrite();
9231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov    data->Backoff();
9331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  }
9431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  return 0;
9531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}
9631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
97ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonovtemplate<typename MutexType>
98ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonovstatic void check_locked(MutexType *mtx) {
99ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov  GenericScopedLock<MutexType> l(mtx);
100ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov  mtx->CheckLocked();
101ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov}
102ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov
10331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry VyukovTEST(SanitizerCommon, SpinMutex) {
10431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  SpinMutex mtx;
10531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  mtx.Init();
10631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  TestData<SpinMutex> data(&mtx);
10731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  pthread_t threads[kThreads];
10831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
11031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_JOIN(threads[i], 0);
11231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}
11331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
11431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry VyukovTEST(SanitizerCommon, SpinMutexTry) {
11531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  SpinMutex mtx;
11631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  mtx.Init();
11731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  TestData<SpinMutex> data(&mtx);
11831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  pthread_t threads[kThreads];
11931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
12131dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_JOIN(threads[i], 0);
12331dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}
12431dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
12531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry VyukovTEST(SanitizerCommon, BlockingMutex) {
12631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  u64 mtxmem[1024] = {};
12731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED);
12831dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  TestData<BlockingMutex> data(mtx);
12931dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  pthread_t threads[kThreads];
13031dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
13231dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov  for (int i = 0; i < kThreads; i++)
1332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_JOIN(threads[i], 0);
134ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov  check_locked(mtx);
13531dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}
13631dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov
13731dc66f6492773e974d32bde84d5d2df9c35a82bDmitry Vyukov}  // namespace __sanitizer
138