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