xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- sanitizer_mutex_test.cpp ------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick #include "sanitizer_common/sanitizer_mutex.h"
133cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
143cab2bb3Spatrick 
153cab2bb3Spatrick #include "sanitizer_pthread_wrappers.h"
163cab2bb3Spatrick 
173cab2bb3Spatrick #include "gtest/gtest.h"
183cab2bb3Spatrick 
193cab2bb3Spatrick #include <string.h>
203cab2bb3Spatrick 
213cab2bb3Spatrick namespace __sanitizer {
223cab2bb3Spatrick 
233cab2bb3Spatrick template<typename MutexType>
243cab2bb3Spatrick class TestData {
253cab2bb3Spatrick  public:
TestData(MutexType * mtx)263cab2bb3Spatrick   explicit TestData(MutexType *mtx)
273cab2bb3Spatrick       : mtx_(mtx) {
283cab2bb3Spatrick     for (int i = 0; i < kSize; i++)
293cab2bb3Spatrick       data_[i] = 0;
303cab2bb3Spatrick   }
313cab2bb3Spatrick 
Write()323cab2bb3Spatrick   void Write() {
333cab2bb3Spatrick     Lock l(mtx_);
343cab2bb3Spatrick     T v0 = data_[0];
353cab2bb3Spatrick     for (int i = 0; i < kSize; i++) {
36d89ec533Spatrick       mtx_->CheckLocked();
373cab2bb3Spatrick       CHECK_EQ(data_[i], v0);
383cab2bb3Spatrick       data_[i]++;
393cab2bb3Spatrick     }
403cab2bb3Spatrick   }
413cab2bb3Spatrick 
TryWrite()423cab2bb3Spatrick   void TryWrite() {
433cab2bb3Spatrick     if (!mtx_->TryLock())
443cab2bb3Spatrick       return;
453cab2bb3Spatrick     T v0 = data_[0];
463cab2bb3Spatrick     for (int i = 0; i < kSize; i++) {
47d89ec533Spatrick       mtx_->CheckLocked();
483cab2bb3Spatrick       CHECK_EQ(data_[i], v0);
493cab2bb3Spatrick       data_[i]++;
503cab2bb3Spatrick     }
513cab2bb3Spatrick     mtx_->Unlock();
523cab2bb3Spatrick   }
533cab2bb3Spatrick 
Read()54d89ec533Spatrick   void Read() {
55d89ec533Spatrick     ReadLock l(mtx_);
56d89ec533Spatrick     T v0 = data_[0];
57d89ec533Spatrick     for (int i = 0; i < kSize; i++) {
58d89ec533Spatrick       mtx_->CheckReadLocked();
59d89ec533Spatrick       CHECK_EQ(data_[i], v0);
60d89ec533Spatrick     }
61d89ec533Spatrick   }
62d89ec533Spatrick 
Backoff()633cab2bb3Spatrick   void Backoff() {
643cab2bb3Spatrick     volatile T data[kSize] = {};
653cab2bb3Spatrick     for (int i = 0; i < kSize; i++) {
663cab2bb3Spatrick       data[i]++;
673cab2bb3Spatrick       CHECK_EQ(data[i], 1);
683cab2bb3Spatrick     }
693cab2bb3Spatrick   }
703cab2bb3Spatrick 
713cab2bb3Spatrick  private:
723cab2bb3Spatrick   typedef GenericScopedLock<MutexType> Lock;
73d89ec533Spatrick   typedef GenericScopedReadLock<MutexType> ReadLock;
743cab2bb3Spatrick   static const int kSize = 64;
753cab2bb3Spatrick   typedef u64 T;
763cab2bb3Spatrick   MutexType *mtx_;
773cab2bb3Spatrick   char pad_[kCacheLineSize];
783cab2bb3Spatrick   T data_[kSize];
793cab2bb3Spatrick };
803cab2bb3Spatrick 
813cab2bb3Spatrick const int kThreads = 8;
823cab2bb3Spatrick #if SANITIZER_DEBUG
833cab2bb3Spatrick const int kIters = 16*1024;
843cab2bb3Spatrick #else
853cab2bb3Spatrick const int kIters = 64*1024;
863cab2bb3Spatrick #endif
873cab2bb3Spatrick 
883cab2bb3Spatrick template<typename MutexType>
lock_thread(void * param)893cab2bb3Spatrick static void *lock_thread(void *param) {
903cab2bb3Spatrick   TestData<MutexType> *data = (TestData<MutexType>*)param;
913cab2bb3Spatrick   for (int i = 0; i < kIters; i++) {
923cab2bb3Spatrick     data->Write();
933cab2bb3Spatrick     data->Backoff();
943cab2bb3Spatrick   }
953cab2bb3Spatrick   return 0;
963cab2bb3Spatrick }
973cab2bb3Spatrick 
983cab2bb3Spatrick template<typename MutexType>
try_thread(void * param)993cab2bb3Spatrick static void *try_thread(void *param) {
1003cab2bb3Spatrick   TestData<MutexType> *data = (TestData<MutexType>*)param;
1013cab2bb3Spatrick   for (int i = 0; i < kIters; i++) {
1023cab2bb3Spatrick     data->TryWrite();
1033cab2bb3Spatrick     data->Backoff();
1043cab2bb3Spatrick   }
1053cab2bb3Spatrick   return 0;
1063cab2bb3Spatrick }
1073cab2bb3Spatrick 
1083cab2bb3Spatrick template <typename MutexType>
read_write_thread(void * param)109d89ec533Spatrick static void *read_write_thread(void *param) {
110d89ec533Spatrick   TestData<MutexType> *data = (TestData<MutexType> *)param;
111d89ec533Spatrick   for (int i = 0; i < kIters; i++) {
112d89ec533Spatrick     if ((i % 10) == 0)
113d89ec533Spatrick       data->Write();
114d89ec533Spatrick     else
115d89ec533Spatrick       data->Read();
116d89ec533Spatrick     data->Backoff();
117d89ec533Spatrick   }
118d89ec533Spatrick   return 0;
119d89ec533Spatrick }
120d89ec533Spatrick 
121d89ec533Spatrick template<typename MutexType>
check_locked(MutexType * mtx)1223cab2bb3Spatrick static void check_locked(MutexType *mtx) {
1233cab2bb3Spatrick   GenericScopedLock<MutexType> l(mtx);
1243cab2bb3Spatrick   mtx->CheckLocked();
1253cab2bb3Spatrick }
1263cab2bb3Spatrick 
TEST(SanitizerCommon,SpinMutex)1273cab2bb3Spatrick TEST(SanitizerCommon, SpinMutex) {
1283cab2bb3Spatrick   SpinMutex mtx;
1293cab2bb3Spatrick   mtx.Init();
1303cab2bb3Spatrick   TestData<SpinMutex> data(&mtx);
1313cab2bb3Spatrick   pthread_t threads[kThreads];
1323cab2bb3Spatrick   for (int i = 0; i < kThreads; i++)
1333cab2bb3Spatrick     PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
1343cab2bb3Spatrick   for (int i = 0; i < kThreads; i++)
1353cab2bb3Spatrick     PTHREAD_JOIN(threads[i], 0);
1363cab2bb3Spatrick }
1373cab2bb3Spatrick 
TEST(SanitizerCommon,SpinMutexTry)1383cab2bb3Spatrick TEST(SanitizerCommon, SpinMutexTry) {
1393cab2bb3Spatrick   SpinMutex mtx;
1403cab2bb3Spatrick   mtx.Init();
1413cab2bb3Spatrick   TestData<SpinMutex> data(&mtx);
1423cab2bb3Spatrick   pthread_t threads[kThreads];
1433cab2bb3Spatrick   for (int i = 0; i < kThreads; i++)
1443cab2bb3Spatrick     PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
1453cab2bb3Spatrick   for (int i = 0; i < kThreads; i++)
1463cab2bb3Spatrick     PTHREAD_JOIN(threads[i], 0);
1473cab2bb3Spatrick }
1483cab2bb3Spatrick 
TEST(SanitizerCommon,Mutex)149d89ec533Spatrick TEST(SanitizerCommon, Mutex) {
150d89ec533Spatrick   Mutex mtx;
151d89ec533Spatrick   TestData<Mutex> data(&mtx);
152d89ec533Spatrick   pthread_t threads[kThreads];
153d89ec533Spatrick   for (int i = 0; i < kThreads; i++)
154d89ec533Spatrick     PTHREAD_CREATE(&threads[i], 0, read_write_thread<Mutex>, &data);
155d89ec533Spatrick   for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);
156d89ec533Spatrick }
157d89ec533Spatrick 
TEST(SanitizerCommon,MutexTry)158*810390e3Srobert TEST(SanitizerCommon, MutexTry) {
159*810390e3Srobert   Mutex mtx;
160*810390e3Srobert   TestData<Mutex> data(&mtx);
161*810390e3Srobert   pthread_t threads[kThreads];
162*810390e3Srobert   for (int i = 0; i < kThreads; i++)
163*810390e3Srobert     PTHREAD_CREATE(&threads[i], 0, try_thread<Mutex>, &data);
164*810390e3Srobert   for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);
165*810390e3Srobert }
166*810390e3Srobert 
167d89ec533Spatrick struct SemaphoreData {
168d89ec533Spatrick   Semaphore *sem;
169d89ec533Spatrick   bool done;
170d89ec533Spatrick };
171d89ec533Spatrick 
SemaphoreThread(void * arg)172d89ec533Spatrick void *SemaphoreThread(void *arg) {
173d89ec533Spatrick   auto data = static_cast<SemaphoreData *>(arg);
174d89ec533Spatrick   data->sem->Wait();
175d89ec533Spatrick   data->done = true;
176d89ec533Spatrick   return nullptr;
177d89ec533Spatrick }
178d89ec533Spatrick 
TEST(SanitizerCommon,Semaphore)179d89ec533Spatrick TEST(SanitizerCommon, Semaphore) {
180d89ec533Spatrick   Semaphore sem;
181d89ec533Spatrick   sem.Post(1);
182d89ec533Spatrick   sem.Wait();
183d89ec533Spatrick   sem.Post(3);
184d89ec533Spatrick   sem.Wait();
185d89ec533Spatrick   sem.Wait();
186d89ec533Spatrick   sem.Wait();
187d89ec533Spatrick 
188d89ec533Spatrick   SemaphoreData data = {&sem, false};
189d89ec533Spatrick   pthread_t thread;
190d89ec533Spatrick   PTHREAD_CREATE(&thread, nullptr, SemaphoreThread, &data);
191d89ec533Spatrick   internal_sleep(1);
192d89ec533Spatrick   CHECK(!data.done);
193d89ec533Spatrick   sem.Post(1);
194d89ec533Spatrick   PTHREAD_JOIN(thread, nullptr);
195d89ec533Spatrick }
196d89ec533Spatrick 
1973cab2bb3Spatrick }  // namespace __sanitizer
198