diff options
Diffstat (limited to 'lib/sanitizer_common/tests/sanitizer_mutex_test.cpp')
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_mutex_test.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/sanitizer_common/tests/sanitizer_mutex_test.cpp b/lib/sanitizer_common/tests/sanitizer_mutex_test.cpp new file mode 100644 index 000000000..2cfbaae63 --- /dev/null +++ b/lib/sanitizer_common/tests/sanitizer_mutex_test.cpp @@ -0,0 +1,136 @@ +//===-- sanitizer_mutex_test.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_common.h" + +#include "sanitizer_pthread_wrappers.h" + +#include "gtest/gtest.h" + +#include <string.h> + +namespace __sanitizer { + +template<typename MutexType> +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<MutexType> Lock; + static const int kSize = 64; + typedef u64 T; + MutexType *mtx_; + char pad_[kCacheLineSize]; + T data_[kSize]; +}; + +const int kThreads = 8; +#if SANITIZER_DEBUG +const int kIters = 16*1024; +#else +const int kIters = 64*1024; +#endif + +template<typename MutexType> +static void *lock_thread(void *param) { + TestData<MutexType> *data = (TestData<MutexType>*)param; + for (int i = 0; i < kIters; i++) { + data->Write(); + data->Backoff(); + } + return 0; +} + +template<typename MutexType> +static void *try_thread(void *param) { + TestData<MutexType> *data = (TestData<MutexType>*)param; + for (int i = 0; i < kIters; i++) { + data->TryWrite(); + data->Backoff(); + } + return 0; +} + +template<typename MutexType> +static void check_locked(MutexType *mtx) { + GenericScopedLock<MutexType> l(mtx); + mtx->CheckLocked(); +} + +TEST(SanitizerCommon, SpinMutex) { + SpinMutex mtx; + mtx.Init(); + TestData<SpinMutex> data(&mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data); + for (int i = 0; i < kThreads; i++) + PTHREAD_JOIN(threads[i], 0); +} + +TEST(SanitizerCommon, SpinMutexTry) { + SpinMutex mtx; + mtx.Init(); + TestData<SpinMutex> data(&mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &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<BlockingMutex> data(mtx); + pthread_t threads[kThreads]; + for (int i = 0; i < kThreads; i++) + PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data); + for (int i = 0; i < kThreads; i++) + PTHREAD_JOIN(threads[i], 0); + check_locked(mtx); +} + +} // namespace __sanitizer |