xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_mutex_test.cpp (revision ea624e697bbe1d2924b69208102c64c4c01e1400)
1d6d569fcSNico Weber //===-- sanitizer_mutex_test.cpp ------------------------------------------===//
2d6d569fcSNico Weber //
3d6d569fcSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d6d569fcSNico Weber // See https://llvm.org/LICENSE.txt for license information.
5d6d569fcSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d6d569fcSNico Weber //
7d6d569fcSNico Weber //===----------------------------------------------------------------------===//
8d6d569fcSNico Weber //
9d6d569fcSNico Weber // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10d6d569fcSNico Weber //
11d6d569fcSNico Weber //===----------------------------------------------------------------------===//
12d6d569fcSNico Weber #include "sanitizer_common/sanitizer_mutex.h"
13d6d569fcSNico Weber #include "sanitizer_common/sanitizer_common.h"
14d6d569fcSNico Weber 
15d6d569fcSNico Weber #include "sanitizer_pthread_wrappers.h"
16d6d569fcSNico Weber 
17d6d569fcSNico Weber #include "gtest/gtest.h"
18d6d569fcSNico Weber 
19d6d569fcSNico Weber #include <string.h>
20d6d569fcSNico Weber 
21d6d569fcSNico Weber namespace __sanitizer {
22d6d569fcSNico Weber 
23d6d569fcSNico Weber template<typename MutexType>
24d6d569fcSNico Weber class TestData {
25d6d569fcSNico Weber  public:
TestData(MutexType * mtx)26d6d569fcSNico Weber   explicit TestData(MutexType *mtx)
27d6d569fcSNico Weber       : mtx_(mtx) {
28d6d569fcSNico Weber     for (int i = 0; i < kSize; i++)
29d6d569fcSNico Weber       data_[i] = 0;
30d6d569fcSNico Weber   }
31d6d569fcSNico Weber 
Write()32d6d569fcSNico Weber   void Write() {
33d6d569fcSNico Weber     Lock l(mtx_);
34d6d569fcSNico Weber     T v0 = data_[0];
35d6d569fcSNico Weber     for (int i = 0; i < kSize; i++) {
363f981fc1SDmitry Vyukov       mtx_->CheckLocked();
37d6d569fcSNico Weber       CHECK_EQ(data_[i], v0);
38d6d569fcSNico Weber       data_[i]++;
39d6d569fcSNico Weber     }
40d6d569fcSNico Weber   }
41d6d569fcSNico Weber 
TryWrite()42d6d569fcSNico Weber   void TryWrite() {
43d6d569fcSNico Weber     if (!mtx_->TryLock())
44d6d569fcSNico Weber       return;
45d6d569fcSNico Weber     T v0 = data_[0];
46d6d569fcSNico Weber     for (int i = 0; i < kSize; i++) {
473f981fc1SDmitry Vyukov       mtx_->CheckLocked();
48d6d569fcSNico Weber       CHECK_EQ(data_[i], v0);
49d6d569fcSNico Weber       data_[i]++;
50d6d569fcSNico Weber     }
51d6d569fcSNico Weber     mtx_->Unlock();
52d6d569fcSNico Weber   }
53d6d569fcSNico Weber 
Read()543f981fc1SDmitry Vyukov   void Read() {
553f981fc1SDmitry Vyukov     ReadLock l(mtx_);
563f981fc1SDmitry Vyukov     T v0 = data_[0];
573f981fc1SDmitry Vyukov     for (int i = 0; i < kSize; i++) {
583f981fc1SDmitry Vyukov       mtx_->CheckReadLocked();
593f981fc1SDmitry Vyukov       CHECK_EQ(data_[i], v0);
603f981fc1SDmitry Vyukov     }
613f981fc1SDmitry Vyukov   }
623f981fc1SDmitry Vyukov 
Backoff()63d6d569fcSNico Weber   void Backoff() {
64d6d569fcSNico Weber     volatile T data[kSize] = {};
65d6d569fcSNico Weber     for (int i = 0; i < kSize; i++) {
66d6d569fcSNico Weber       data[i]++;
67d6d569fcSNico Weber       CHECK_EQ(data[i], 1);
68d6d569fcSNico Weber     }
69d6d569fcSNico Weber   }
70d6d569fcSNico Weber 
71d6d569fcSNico Weber  private:
72d6d569fcSNico Weber   typedef GenericScopedLock<MutexType> Lock;
733f981fc1SDmitry Vyukov   typedef GenericScopedReadLock<MutexType> ReadLock;
74d6d569fcSNico Weber   static const int kSize = 64;
75d6d569fcSNico Weber   typedef u64 T;
76d6d569fcSNico Weber   MutexType *mtx_;
77d6d569fcSNico Weber   char pad_[kCacheLineSize];
78d6d569fcSNico Weber   T data_[kSize];
79d6d569fcSNico Weber };
80d6d569fcSNico Weber 
81d6d569fcSNico Weber const int kThreads = 8;
82d6d569fcSNico Weber #if SANITIZER_DEBUG
83d6d569fcSNico Weber const int kIters = 16*1024;
84d6d569fcSNico Weber #else
85d6d569fcSNico Weber const int kIters = 64*1024;
86d6d569fcSNico Weber #endif
87d6d569fcSNico Weber 
88d6d569fcSNico Weber template<typename MutexType>
lock_thread(void * param)89d6d569fcSNico Weber static void *lock_thread(void *param) {
90d6d569fcSNico Weber   TestData<MutexType> *data = (TestData<MutexType>*)param;
91d6d569fcSNico Weber   for (int i = 0; i < kIters; i++) {
92d6d569fcSNico Weber     data->Write();
93d6d569fcSNico Weber     data->Backoff();
94d6d569fcSNico Weber   }
95d6d569fcSNico Weber   return 0;
96d6d569fcSNico Weber }
97d6d569fcSNico Weber 
98d6d569fcSNico Weber template<typename MutexType>
try_thread(void * param)99d6d569fcSNico Weber static void *try_thread(void *param) {
100d6d569fcSNico Weber   TestData<MutexType> *data = (TestData<MutexType>*)param;
101d6d569fcSNico Weber   for (int i = 0; i < kIters; i++) {
102d6d569fcSNico Weber     data->TryWrite();
103d6d569fcSNico Weber     data->Backoff();
104d6d569fcSNico Weber   }
105d6d569fcSNico Weber   return 0;
106d6d569fcSNico Weber }
107d6d569fcSNico Weber 
108d6d569fcSNico Weber template <typename MutexType>
read_write_thread(void * param)1093f981fc1SDmitry Vyukov static void *read_write_thread(void *param) {
1103f981fc1SDmitry Vyukov   TestData<MutexType> *data = (TestData<MutexType> *)param;
1113f981fc1SDmitry Vyukov   for (int i = 0; i < kIters; i++) {
1123f981fc1SDmitry Vyukov     if ((i % 10) == 0)
1133f981fc1SDmitry Vyukov       data->Write();
1143f981fc1SDmitry Vyukov     else
1153f981fc1SDmitry Vyukov       data->Read();
1163f981fc1SDmitry Vyukov     data->Backoff();
1173f981fc1SDmitry Vyukov   }
1183f981fc1SDmitry Vyukov   return 0;
1193f981fc1SDmitry Vyukov }
1203f981fc1SDmitry Vyukov 
1213f981fc1SDmitry Vyukov template<typename MutexType>
check_locked(MutexType * mtx)122d6d569fcSNico Weber static void check_locked(MutexType *mtx) {
123d6d569fcSNico Weber   GenericScopedLock<MutexType> l(mtx);
124d6d569fcSNico Weber   mtx->CheckLocked();
125d6d569fcSNico Weber }
126d6d569fcSNico Weber 
TEST(SanitizerCommon,SpinMutex)127d6d569fcSNico Weber TEST(SanitizerCommon, SpinMutex) {
128d6d569fcSNico Weber   SpinMutex mtx;
129d6d569fcSNico Weber   mtx.Init();
130d6d569fcSNico Weber   TestData<SpinMutex> data(&mtx);
131d6d569fcSNico Weber   pthread_t threads[kThreads];
132d6d569fcSNico Weber   for (int i = 0; i < kThreads; i++)
133d6d569fcSNico Weber     PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
134d6d569fcSNico Weber   for (int i = 0; i < kThreads; i++)
135d6d569fcSNico Weber     PTHREAD_JOIN(threads[i], 0);
136d6d569fcSNico Weber }
137d6d569fcSNico Weber 
TEST(SanitizerCommon,SpinMutexTry)138d6d569fcSNico Weber TEST(SanitizerCommon, SpinMutexTry) {
139d6d569fcSNico Weber   SpinMutex mtx;
140d6d569fcSNico Weber   mtx.Init();
141d6d569fcSNico Weber   TestData<SpinMutex> data(&mtx);
142d6d569fcSNico Weber   pthread_t threads[kThreads];
143d6d569fcSNico Weber   for (int i = 0; i < kThreads; i++)
144d6d569fcSNico Weber     PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
145d6d569fcSNico Weber   for (int i = 0; i < kThreads; i++)
146d6d569fcSNico Weber     PTHREAD_JOIN(threads[i], 0);
147d6d569fcSNico Weber }
148d6d569fcSNico Weber 
TEST(SanitizerCommon,Mutex)1490118a649SDmitry Vyukov TEST(SanitizerCommon, Mutex) {
1500118a649SDmitry Vyukov   Mutex mtx;
1510118a649SDmitry Vyukov   TestData<Mutex> data(&mtx);
1523f981fc1SDmitry Vyukov   pthread_t threads[kThreads];
1533f981fc1SDmitry Vyukov   for (int i = 0; i < kThreads; i++)
1540118a649SDmitry Vyukov     PTHREAD_CREATE(&threads[i], 0, read_write_thread<Mutex>, &data);
1553f981fc1SDmitry Vyukov   for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);
1563f981fc1SDmitry Vyukov }
1573f981fc1SDmitry Vyukov 
TEST(SanitizerCommon,MutexTry)158*ea624e69SDmitry Vyukov TEST(SanitizerCommon, MutexTry) {
159*ea624e69SDmitry Vyukov   Mutex mtx;
160*ea624e69SDmitry Vyukov   TestData<Mutex> data(&mtx);
161*ea624e69SDmitry Vyukov   pthread_t threads[kThreads];
162*ea624e69SDmitry Vyukov   for (int i = 0; i < kThreads; i++)
163*ea624e69SDmitry Vyukov     PTHREAD_CREATE(&threads[i], 0, try_thread<Mutex>, &data);
164*ea624e69SDmitry Vyukov   for (int i = 0; i < kThreads; i++) PTHREAD_JOIN(threads[i], 0);
165*ea624e69SDmitry Vyukov }
166*ea624e69SDmitry Vyukov 
1676a4054efSDmitry Vyukov struct SemaphoreData {
1686a4054efSDmitry Vyukov   Semaphore *sem;
1696a4054efSDmitry Vyukov   bool done;
1706a4054efSDmitry Vyukov };
1716a4054efSDmitry Vyukov 
SemaphoreThread(void * arg)1726a4054efSDmitry Vyukov void *SemaphoreThread(void *arg) {
1736a4054efSDmitry Vyukov   auto data = static_cast<SemaphoreData *>(arg);
1746a4054efSDmitry Vyukov   data->sem->Wait();
1756a4054efSDmitry Vyukov   data->done = true;
1766a4054efSDmitry Vyukov   return nullptr;
1776a4054efSDmitry Vyukov }
1786a4054efSDmitry Vyukov 
TEST(SanitizerCommon,Semaphore)1796a4054efSDmitry Vyukov TEST(SanitizerCommon, Semaphore) {
1806a4054efSDmitry Vyukov   Semaphore sem;
1816a4054efSDmitry Vyukov   sem.Post(1);
1826a4054efSDmitry Vyukov   sem.Wait();
1836a4054efSDmitry Vyukov   sem.Post(3);
1846a4054efSDmitry Vyukov   sem.Wait();
1856a4054efSDmitry Vyukov   sem.Wait();
1866a4054efSDmitry Vyukov   sem.Wait();
1876a4054efSDmitry Vyukov 
1886a4054efSDmitry Vyukov   SemaphoreData data = {&sem, false};
1896a4054efSDmitry Vyukov   pthread_t thread;
1906a4054efSDmitry Vyukov   PTHREAD_CREATE(&thread, nullptr, SemaphoreThread, &data);
191c14f2684SVitaly Buka   internal_sleep(1);
1926a4054efSDmitry Vyukov   CHECK(!data.done);
1936a4054efSDmitry Vyukov   sem.Post(1);
1946a4054efSDmitry Vyukov   PTHREAD_JOIN(thread, nullptr);
1956a4054efSDmitry Vyukov }
1966a4054efSDmitry Vyukov 
197d6d569fcSNico Weber }  // namespace __sanitizer
198