xref: /aosp_15_r20/external/cronet/base/synchronization/lock_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/test/gtest_util.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
13*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker class BasicLockTestThread : public PlatformThread::Delegate {
20*6777b538SAndroid Build Coastguard Worker  public:
BasicLockTestThread(Lock * lock)21*6777b538SAndroid Build Coastguard Worker   explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker   BasicLockTestThread(const BasicLockTestThread&) = delete;
24*6777b538SAndroid Build Coastguard Worker   BasicLockTestThread& operator=(const BasicLockTestThread&) = delete;
25*6777b538SAndroid Build Coastguard Worker 
ThreadMain()26*6777b538SAndroid Build Coastguard Worker   void ThreadMain() override {
27*6777b538SAndroid Build Coastguard Worker     for (int i = 0; i < 10; i++) {
28*6777b538SAndroid Build Coastguard Worker       lock_->Acquire();
29*6777b538SAndroid Build Coastguard Worker       acquired_++;
30*6777b538SAndroid Build Coastguard Worker       lock_->Release();
31*6777b538SAndroid Build Coastguard Worker     }
32*6777b538SAndroid Build Coastguard Worker     for (int i = 0; i < 10; i++) {
33*6777b538SAndroid Build Coastguard Worker       lock_->Acquire();
34*6777b538SAndroid Build Coastguard Worker       acquired_++;
35*6777b538SAndroid Build Coastguard Worker       PlatformThread::Sleep(Milliseconds(rand() % 20));
36*6777b538SAndroid Build Coastguard Worker       lock_->Release();
37*6777b538SAndroid Build Coastguard Worker     }
38*6777b538SAndroid Build Coastguard Worker     for (int i = 0; i < 10; i++) {
39*6777b538SAndroid Build Coastguard Worker       if (lock_->Try()) {
40*6777b538SAndroid Build Coastguard Worker         acquired_++;
41*6777b538SAndroid Build Coastguard Worker         PlatformThread::Sleep(Milliseconds(rand() % 20));
42*6777b538SAndroid Build Coastguard Worker         lock_->Release();
43*6777b538SAndroid Build Coastguard Worker       }
44*6777b538SAndroid Build Coastguard Worker     }
45*6777b538SAndroid Build Coastguard Worker   }
46*6777b538SAndroid Build Coastguard Worker 
acquired() const47*6777b538SAndroid Build Coastguard Worker   int acquired() const { return acquired_; }
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker  private:
50*6777b538SAndroid Build Coastguard Worker   raw_ptr<Lock> lock_;
51*6777b538SAndroid Build Coastguard Worker   int acquired_;
52*6777b538SAndroid Build Coastguard Worker };
53*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,Basic)54*6777b538SAndroid Build Coastguard Worker TEST(LockTest, Basic) {
55*6777b538SAndroid Build Coastguard Worker   Lock lock;
56*6777b538SAndroid Build Coastguard Worker   BasicLockTestThread thread(&lock);
57*6777b538SAndroid Build Coastguard Worker   PlatformThreadHandle handle;
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker   int acquired = 0;
62*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < 5; i++) {
63*6777b538SAndroid Build Coastguard Worker     lock.Acquire();
64*6777b538SAndroid Build Coastguard Worker     acquired++;
65*6777b538SAndroid Build Coastguard Worker     lock.Release();
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < 10; i++) {
68*6777b538SAndroid Build Coastguard Worker     lock.Acquire();
69*6777b538SAndroid Build Coastguard Worker     acquired++;
70*6777b538SAndroid Build Coastguard Worker     PlatformThread::Sleep(Milliseconds(rand() % 20));
71*6777b538SAndroid Build Coastguard Worker     lock.Release();
72*6777b538SAndroid Build Coastguard Worker   }
73*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < 10; i++) {
74*6777b538SAndroid Build Coastguard Worker     if (lock.Try()) {
75*6777b538SAndroid Build Coastguard Worker       acquired++;
76*6777b538SAndroid Build Coastguard Worker       PlatformThread::Sleep(Milliseconds(rand() % 20));
77*6777b538SAndroid Build Coastguard Worker       lock.Release();
78*6777b538SAndroid Build Coastguard Worker     }
79*6777b538SAndroid Build Coastguard Worker   }
80*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < 5; i++) {
81*6777b538SAndroid Build Coastguard Worker     lock.Acquire();
82*6777b538SAndroid Build Coastguard Worker     acquired++;
83*6777b538SAndroid Build Coastguard Worker     PlatformThread::Sleep(Milliseconds(rand() % 20));
84*6777b538SAndroid Build Coastguard Worker     lock.Release();
85*6777b538SAndroid Build Coastguard Worker   }
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker   PlatformThread::Join(handle);
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker   EXPECT_GE(acquired, 20);
90*6777b538SAndroid Build Coastguard Worker   EXPECT_GE(thread.acquired(), 20);
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker // Test that Try() works as expected -------------------------------------------
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker class TryLockTestThread : public PlatformThread::Delegate {
96*6777b538SAndroid Build Coastguard Worker  public:
TryLockTestThread(Lock * lock)97*6777b538SAndroid Build Coastguard Worker   explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker   TryLockTestThread(const TryLockTestThread&) = delete;
100*6777b538SAndroid Build Coastguard Worker   TryLockTestThread& operator=(const TryLockTestThread&) = delete;
101*6777b538SAndroid Build Coastguard Worker 
ThreadMain()102*6777b538SAndroid Build Coastguard Worker   void ThreadMain() override {
103*6777b538SAndroid Build Coastguard Worker     // The local variable is required for the static analyzer to see that the
104*6777b538SAndroid Build Coastguard Worker     // lock is properly released.
105*6777b538SAndroid Build Coastguard Worker     bool got_lock = lock_->Try();
106*6777b538SAndroid Build Coastguard Worker     got_lock_ = got_lock;
107*6777b538SAndroid Build Coastguard Worker     if (got_lock)
108*6777b538SAndroid Build Coastguard Worker       lock_->Release();
109*6777b538SAndroid Build Coastguard Worker   }
110*6777b538SAndroid Build Coastguard Worker 
got_lock() const111*6777b538SAndroid Build Coastguard Worker   bool got_lock() const { return got_lock_; }
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker  private:
114*6777b538SAndroid Build Coastguard Worker   raw_ptr<Lock> lock_;
115*6777b538SAndroid Build Coastguard Worker   bool got_lock_;
116*6777b538SAndroid Build Coastguard Worker };
117*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,TryLock)118*6777b538SAndroid Build Coastguard Worker TEST(LockTest, TryLock) {
119*6777b538SAndroid Build Coastguard Worker   Lock lock;
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(lock.Try());
122*6777b538SAndroid Build Coastguard Worker   lock.AssertAcquired();
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker   // This thread will not be able to get the lock.
125*6777b538SAndroid Build Coastguard Worker   {
126*6777b538SAndroid Build Coastguard Worker     TryLockTestThread thread(&lock);
127*6777b538SAndroid Build Coastguard Worker     PlatformThreadHandle handle;
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker     PlatformThread::Join(handle);
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker     ASSERT_FALSE(thread.got_lock());
134*6777b538SAndroid Build Coastguard Worker   }
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker   lock.Release();
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   // This thread will....
139*6777b538SAndroid Build Coastguard Worker   {
140*6777b538SAndroid Build Coastguard Worker     TryLockTestThread thread(&lock);
141*6777b538SAndroid Build Coastguard Worker     PlatformThreadHandle handle;
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker     PlatformThread::Join(handle);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(thread.got_lock());
148*6777b538SAndroid Build Coastguard Worker     // But it released it....
149*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(lock.Try());
150*6777b538SAndroid Build Coastguard Worker     lock.AssertAcquired();
151*6777b538SAndroid Build Coastguard Worker   }
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   lock.Release();
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker // Tests that locks actually exclude -------------------------------------------
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker class MutexLockTestThread : public PlatformThread::Delegate {
159*6777b538SAndroid Build Coastguard Worker  public:
MutexLockTestThread(Lock * lock,int * value)160*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread(const MutexLockTestThread&) = delete;
163*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread& operator=(const MutexLockTestThread&) = delete;
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker   // Static helper which can also be called from the main thread.
DoStuff(Lock * lock,int * value)166*6777b538SAndroid Build Coastguard Worker   static void DoStuff(Lock* lock, int* value) {
167*6777b538SAndroid Build Coastguard Worker     for (int i = 0; i < 40; i++) {
168*6777b538SAndroid Build Coastguard Worker       lock->Acquire();
169*6777b538SAndroid Build Coastguard Worker       int v = *value;
170*6777b538SAndroid Build Coastguard Worker       PlatformThread::Sleep(Milliseconds(rand() % 10));
171*6777b538SAndroid Build Coastguard Worker       *value = v + 1;
172*6777b538SAndroid Build Coastguard Worker       lock->Release();
173*6777b538SAndroid Build Coastguard Worker     }
174*6777b538SAndroid Build Coastguard Worker   }
175*6777b538SAndroid Build Coastguard Worker 
ThreadMain()176*6777b538SAndroid Build Coastguard Worker   void ThreadMain() override { DoStuff(lock_, value_); }
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker  private:
179*6777b538SAndroid Build Coastguard Worker   raw_ptr<Lock> lock_;
180*6777b538SAndroid Build Coastguard Worker   raw_ptr<int> value_;
181*6777b538SAndroid Build Coastguard Worker };
182*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,MutexTwoThreads)183*6777b538SAndroid Build Coastguard Worker TEST(LockTest, MutexTwoThreads) {
184*6777b538SAndroid Build Coastguard Worker   Lock lock;
185*6777b538SAndroid Build Coastguard Worker   int value = 0;
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread thread(&lock, &value);
188*6777b538SAndroid Build Coastguard Worker   PlatformThreadHandle handle;
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
191*6777b538SAndroid Build Coastguard Worker 
192*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread::DoStuff(&lock, &value);
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   PlatformThread::Join(handle);
195*6777b538SAndroid Build Coastguard Worker 
196*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(2 * 40, value);
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,MutexFourThreads)199*6777b538SAndroid Build Coastguard Worker TEST(LockTest, MutexFourThreads) {
200*6777b538SAndroid Build Coastguard Worker   Lock lock;
201*6777b538SAndroid Build Coastguard Worker   int value = 0;
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread thread1(&lock, &value);
204*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread thread2(&lock, &value);
205*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread thread3(&lock, &value);
206*6777b538SAndroid Build Coastguard Worker   PlatformThreadHandle handle1;
207*6777b538SAndroid Build Coastguard Worker   PlatformThreadHandle handle2;
208*6777b538SAndroid Build Coastguard Worker   PlatformThreadHandle handle3;
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
211*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
212*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
213*6777b538SAndroid Build Coastguard Worker 
214*6777b538SAndroid Build Coastguard Worker   MutexLockTestThread::DoStuff(&lock, &value);
215*6777b538SAndroid Build Coastguard Worker 
216*6777b538SAndroid Build Coastguard Worker   PlatformThread::Join(handle1);
217*6777b538SAndroid Build Coastguard Worker   PlatformThread::Join(handle2);
218*6777b538SAndroid Build Coastguard Worker   PlatformThread::Join(handle3);
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(4 * 40, value);
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,AutoLockMaybe)223*6777b538SAndroid Build Coastguard Worker TEST(LockTest, AutoLockMaybe) {
224*6777b538SAndroid Build Coastguard Worker   Lock lock;
225*6777b538SAndroid Build Coastguard Worker   {
226*6777b538SAndroid Build Coastguard Worker     AutoLockMaybe auto_lock(&lock);
227*6777b538SAndroid Build Coastguard Worker     lock.AssertAcquired();
228*6777b538SAndroid Build Coastguard Worker   }
229*6777b538SAndroid Build Coastguard Worker   EXPECT_DCHECK_DEATH(lock.AssertAcquired());
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,AutoLockMaybeNull)232*6777b538SAndroid Build Coastguard Worker TEST(LockTest, AutoLockMaybeNull) {
233*6777b538SAndroid Build Coastguard Worker   AutoLockMaybe auto_lock(nullptr);
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,ReleasableAutoLockExplicitRelease)236*6777b538SAndroid Build Coastguard Worker TEST(LockTest, ReleasableAutoLockExplicitRelease) {
237*6777b538SAndroid Build Coastguard Worker   Lock lock;
238*6777b538SAndroid Build Coastguard Worker   ReleasableAutoLock auto_lock(&lock);
239*6777b538SAndroid Build Coastguard Worker   lock.AssertAcquired();
240*6777b538SAndroid Build Coastguard Worker   auto_lock.Release();
241*6777b538SAndroid Build Coastguard Worker   EXPECT_DCHECK_DEATH(lock.AssertAcquired());
242*6777b538SAndroid Build Coastguard Worker }
243*6777b538SAndroid Build Coastguard Worker 
TEST(LockTest,ReleasableAutoLockImplicitRelease)244*6777b538SAndroid Build Coastguard Worker TEST(LockTest, ReleasableAutoLockImplicitRelease) {
245*6777b538SAndroid Build Coastguard Worker   Lock lock;
246*6777b538SAndroid Build Coastguard Worker   {
247*6777b538SAndroid Build Coastguard Worker     ReleasableAutoLock auto_lock(&lock);
248*6777b538SAndroid Build Coastguard Worker     lock.AssertAcquired();
249*6777b538SAndroid Build Coastguard Worker   }
250*6777b538SAndroid Build Coastguard Worker   EXPECT_DCHECK_DEATH(lock.AssertAcquired());
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker }  // namespace base
254