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