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