//===-- tsan_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 (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" #include "tsan_mutex.h" #include "gtest/gtest.h" namespace __tsan { 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 Read() { ReadLock l(mtx_); T v0 = data_[0]; for (int i = 0; i < kSize; i++) { CHECK_EQ(data_[i], v0); } } 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; const int kWriteRate = 1024; #if SANITIZER_DEBUG const int kIters = 16*1024; #else const int kIters = 64*1024; #endif template<typename MutexType> static void *write_mutex_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 *read_mutex_thread(void *param) { TestData<MutexType> *data = (TestData<MutexType>*)param; for (int i = 0; i < kIters; i++) { if ((i % kWriteRate) == 0) data->Write(); else data->Read(); data->Backoff(); } return 0; } TEST(Mutex, Write) { Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations); TestData<Mutex> data(&mtx); pthread_t threads[kThreads]; for (int i = 0; i < kThreads; i++) pthread_create(&threads[i], 0, write_mutex_thread<Mutex>, &data); for (int i = 0; i < kThreads; i++) pthread_join(threads[i], 0); } TEST(Mutex, ReadWrite) { Mutex mtx(MutexTypeAnnotations, StatMtxAnnotations); TestData<Mutex> data(&mtx); pthread_t threads[kThreads]; for (int i = 0; i < kThreads; i++) pthread_create(&threads[i], 0, read_mutex_thread<Mutex>, &data); for (int i = 0; i < kThreads; i++) pthread_join(threads[i], 0); } TEST(Mutex, SpinWrite) { SpinMutex mtx; TestData<SpinMutex> data(&mtx); pthread_t threads[kThreads]; for (int i = 0; i < kThreads; i++) pthread_create(&threads[i], 0, write_mutex_thread<SpinMutex>, &data); for (int i = 0; i < kThreads; i++) pthread_join(threads[i], 0); } } // namespace __tsan