198 lines · cpp
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-exception6//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 21namespace __sanitizer {22 23template<typename MutexType>24class 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 mtx_->CheckLocked();37 CHECK_EQ(data_[i], v0);38 data_[i]++;39 }40 }41 42 void TryWrite() {43 if (!mtx_->TryLock())44 return;45 T v0 = data_[0];46 for (int i = 0; i < kSize; i++) {47 mtx_->CheckLocked();48 CHECK_EQ(data_[i], v0);49 data_[i]++;50 }51 mtx_->Unlock();52 }53 54 void Read() {55 ReadLock l(mtx_);56 T v0 = data_[0];57 for (int i = 0; i < kSize; i++) {58 mtx_->CheckReadLocked();59 CHECK_EQ(data_[i], v0);60 }61 }62 63 void Backoff() {64 volatile T data[kSize] = {};65 for (int i = 0; i < kSize; i++) {66 data[i]++;67 CHECK_EQ(data[i], 1);68 }69 }70 71 private:72 typedef GenericScopedLock<MutexType> Lock;73 typedef GenericScopedReadLock<MutexType> ReadLock;74 static const int kSize = 64;75 typedef u64 T;76 MutexType *mtx_;77 char pad_[kCacheLineSize];78 T data_[kSize];79};80 81const int kThreads = 8;82#if SANITIZER_DEBUG83const int kIters = 16*1024;84#else85const int kIters = 64*1024;86#endif87 88template<typename MutexType>89static void *lock_thread(void *param) {90 TestData<MutexType> *data = (TestData<MutexType>*)param;91 for (int i = 0; i < kIters; i++) {92 data->Write();93 data->Backoff();94 }95 return 0;96}97 98template<typename MutexType>99static void *try_thread(void *param) {100 TestData<MutexType> *data = (TestData<MutexType>*)param;101 for (int i = 0; i < kIters; i++) {102 data->TryWrite();103 data->Backoff();104 }105 return 0;106}107 108template <typename MutexType>109static void *read_write_thread(void *param) {110 TestData<MutexType> *data = (TestData<MutexType> *)param;111 for (int i = 0; i < kIters; i++) {112 if ((i % 10) == 0)113 data->Write();114 else115 data->Read();116 data->Backoff();117 }118 return 0;119}120 121template<typename MutexType>122static void check_locked(MutexType *mtx) {123 GenericScopedLock<MutexType> l(mtx);124 mtx->CheckLocked();125}126 127TEST(SanitizerCommon, SpinMutex) {128 SpinMutex mtx;129 mtx.Init();130 TestData<SpinMutex> data(&mtx);131 pthread_t threads[kThreads];132 for (int i = 0; i < kThreads; i++)133 PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);134 for (int i = 0; i < kThreads; i++)135 PTHREAD_JOIN(threads[i], 0);136}137 138TEST(SanitizerCommon, SpinMutexTry) {139 SpinMutex mtx;140 mtx.Init();141 TestData<SpinMutex> data(&mtx);142 pthread_t threads[kThreads];143 for (int i = 0; i < kThreads; i++)144 PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);145 for (int i = 0; i < kThreads; i++)146 PTHREAD_JOIN(threads[i], 0);147}148 149TEST(SanitizerCommon, Mutex) {150 Mutex mtx;151 TestData<Mutex> data(&mtx);152 pthread_t threads[kThreads];153 for (int i = 0; i < kThreads; i++)154 PTHREAD_CREATE(&threads[i], 0, read_write_thread<Mutex>, &data);155 for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);156}157 158TEST(SanitizerCommon, MutexTry) {159 Mutex mtx;160 TestData<Mutex> data(&mtx);161 pthread_t threads[kThreads];162 for (int i = 0; i < kThreads; i++)163 PTHREAD_CREATE(&threads[i], 0, try_thread<Mutex>, &data);164 for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);165}166 167struct SemaphoreData {168 Semaphore *sem;169 bool done;170};171 172void *SemaphoreThread(void *arg) {173 auto data = static_cast<SemaphoreData *>(arg);174 data->sem->Wait();175 data->done = true;176 return nullptr;177}178 179TEST(SanitizerCommon, Semaphore) {180 Semaphore sem;181 sem.Post(1);182 sem.Wait();183 sem.Post(3);184 sem.Wait();185 sem.Wait();186 sem.Wait();187 188 SemaphoreData data = {&sem, false};189 pthread_t thread;190 PTHREAD_CREATE(&thread, nullptr, SemaphoreThread, &data);191 internal_sleep(1);192 CHECK(!data.done);193 sem.Post(1);194 PTHREAD_JOIN(thread, nullptr);195}196 197} // namespace __sanitizer198