diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc new file mode 100644 index 000000000000..6bb2ae29a188 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cc @@ -0,0 +1,128 @@ +//===-- sanitizer_mutex_test.cc -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_common.h" +#include "gtest/gtest.h" + +#include + +namespace __sanitizer { + +template +class TestData { + public: + explicit TestData(MutexType *mtx) + : mtx_(mtx) { + for (int i = 0; i < kSize; i++) + data_[i] = 0; + } + + void Write() { + Lock l(mtx_); + T v0 = data_[0]; + for (int i = 0; i < kSize; i++) { + CHECK_EQ(data_[i], v0); + data_[i]++; + } + } + + void TryWrite() { + if (!mtx_->TryLock()) + return; + T v0 = data_[0]; + for (int i = 0; i < kSize; i++) { + CHECK_EQ(data_[i], v0); + data_[i]++; + } + mtx_->Unlock(); + } + + void Backoff() { + volatile T data[kSize] = {}; + for (int i = 0; i < kSize; i++) { + data[i]++; + CHECK_EQ(data[i], 1); + } + } + + private: + typedef GenericScopedLock Lock; + static const int kSize = 64; + typedef u64 T; + MutexType *mtx_; + char pad_[kCacheLineSize]; + T data_[kSize]; +}; + +const int kThreads = 8; +const int kWriteRate = 1024; +#if SANITIZER_DEBUG +const int kIters = 16*1024; +#else +const int kIters = 64*1024; +#endif + +template +static void *lock_thread(void *param) { + TestData *data = (TestData*)param; + for (int i = 0; i < kIters; i++) { + data->Write(); + data->Backoff(); + } + return 0; +} + +template +static void *try_thread(void *param) { + TestData *data = (TestData*)param; + for (int i = 0; i < kIters; i++) { + data->TryWrite(); + data->Backoff(); + } + return 0; +} + +TEST(SanitizerCommon, SpinMutex) { + SpinMutex mtx; + mtx.Init(); + TestData data(&mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + pthread_create(&threads[i], 0, lock_thread, &data); + for (int i = 0; i < kThreads; i++) + pthread_join(threads[i], 0); +} + +TEST(SanitizerCommon, SpinMutexTry) { + SpinMutex mtx; + mtx.Init(); + TestData data(&mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + pthread_create(&threads[i], 0, try_thread, &data); + for (int i = 0; i < kThreads; i++) + pthread_join(threads[i], 0); +} + +TEST(SanitizerCommon, BlockingMutex) { + u64 mtxmem[1024] = {}; + BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED); + TestData data(mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + pthread_create(&threads[i], 0, lock_thread, &data); + for (int i = 0; i < kThreads; i++) + pthread_join(threads[i], 0); +} + +} // namespace __sanitizer