1//===-- mutex_test.cpp ------------------------------------------*- C++ -*-===//
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#include "tests/scudo_unit_test.h"
10
11#include "mutex.h"
12
13#include <pthread.h>
14#include <string.h>
15
16class TestData {
17public:
18  explicit TestData(scudo::HybridMutex &M) : Mutex(M) {
19    for (scudo::u32 I = 0; I < Size; I++)
20      Data[I] = 0;
21  }
22
23  void write() {
24    scudo::ScopedLock L(Mutex);
25    T V0 = Data[0];
26    for (scudo::u32 I = 0; I < Size; I++) {
27      EXPECT_EQ(Data[I], V0);
28      Data[I]++;
29    }
30  }
31
32  void tryWrite() {
33    if (!Mutex.tryLock())
34      return;
35    T V0 = Data[0];
36    for (scudo::u32 I = 0; I < Size; I++) {
37      EXPECT_EQ(Data[I], V0);
38      Data[I]++;
39    }
40    Mutex.unlock();
41  }
42
43  void backoff() {
44    volatile T LocalData[Size] = {};
45    for (scudo::u32 I = 0; I < Size; I++) {
46      LocalData[I] = LocalData[I] + 1;
47      EXPECT_EQ(LocalData[I], 1U);
48    }
49  }
50
51private:
52  static const scudo::u32 Size = 64U;
53  typedef scudo::u64 T;
54  scudo::HybridMutex &Mutex;
55  alignas(SCUDO_CACHE_LINE_SIZE) T Data[Size];
56};
57
58const scudo::u32 NumberOfThreads = 8;
59#if SCUDO_DEBUG
60const scudo::u32 NumberOfIterations = 4 * 1024;
61#else
62const scudo::u32 NumberOfIterations = 16 * 1024;
63#endif
64
65static void *lockThread(void *Param) {
66  TestData *Data = reinterpret_cast<TestData *>(Param);
67  for (scudo::u32 I = 0; I < NumberOfIterations; I++) {
68    Data->write();
69    Data->backoff();
70  }
71  return 0;
72}
73
74static void *tryThread(void *Param) {
75  TestData *Data = reinterpret_cast<TestData *>(Param);
76  for (scudo::u32 I = 0; I < NumberOfIterations; I++) {
77    Data->tryWrite();
78    Data->backoff();
79  }
80  return 0;
81}
82
83TEST(ScudoMutexTest, Mutex) {
84  scudo::HybridMutex M;
85  TestData Data(M);
86  pthread_t Threads[NumberOfThreads];
87  for (scudo::u32 I = 0; I < NumberOfThreads; I++)
88    pthread_create(&Threads[I], 0, lockThread, &Data);
89  for (scudo::u32 I = 0; I < NumberOfThreads; I++)
90    pthread_join(Threads[I], 0);
91}
92
93TEST(ScudoMutexTest, MutexTry) {
94  scudo::HybridMutex M;
95  TestData Data(M);
96  pthread_t Threads[NumberOfThreads];
97  for (scudo::u32 I = 0; I < NumberOfThreads; I++)
98    pthread_create(&Threads[I], 0, tryThread, &Data);
99  for (scudo::u32 I = 0; I < NumberOfThreads; I++)
100    pthread_join(Threads[I], 0);
101}
102