1 /*
2 * Copyright 2011 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18
19 #include "gtest/gtest.h"
20 #include "sfntly/port/lock.h"
21 #include "test/platform_thread.h"
22
23 namespace sfntly {
24
25 // Basic test to make sure that Acquire()/Unlock()/Try() don't crash
26
27 class BasicLockTestThread : public PlatformThread::Delegate {
28 public:
BasicLockTestThread(Lock * lock)29 BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
30
ThreadMain()31 virtual void ThreadMain() {
32 for (int i = 0; i < 10; i++) {
33 lock_->Acquire();
34 acquired_++;
35 lock_->Unlock();
36 }
37 for (int i = 0; i < 10; i++) {
38 lock_->Acquire();
39 acquired_++;
40 PlatformThread::Sleep(rand() % 20);
41 lock_->Unlock();
42 }
43 for (int i = 0; i < 10; i++) {
44 if (lock_->Try()) {
45 acquired_++;
46 PlatformThread::Sleep(rand() % 20);
47 lock_->Unlock();
48 }
49 }
50 }
51
acquired() const52 int acquired() const { return acquired_; }
53
54 private:
55 Lock* lock_;
56 int acquired_;
57
58 NO_COPY_AND_ASSIGN(BasicLockTestThread);
59 };
60
BasicLockTest()61 bool BasicLockTest() {
62 Lock lock;
63 BasicLockTestThread thread(&lock);
64 PlatformThreadHandle handle = kNullThreadHandle;
65
66 EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
67
68 int acquired = 0;
69 for (int i = 0; i < 5; i++) {
70 lock.Acquire();
71 acquired++;
72 lock.Unlock();
73 }
74 for (int i = 0; i < 10; i++) {
75 lock.Acquire();
76 acquired++;
77 PlatformThread::Sleep(rand() % 20);
78 lock.Unlock();
79 }
80 for (int i = 0; i < 10; i++) {
81 if (lock.Try()) {
82 acquired++;
83 PlatformThread::Sleep(rand() % 20);
84 lock.Unlock();
85 }
86 }
87 for (int i = 0; i < 5; i++) {
88 lock.Acquire();
89 acquired++;
90 PlatformThread::Sleep(rand() % 20);
91 lock.Unlock();
92 }
93
94 PlatformThread::Join(handle);
95
96 EXPECT_GE(acquired, 20);
97 EXPECT_GE(thread.acquired(), 20);
98
99 return true;
100 }
101
102 // Test that Try() works as expected -------------------------------------------
103
104 class TryLockTestThread : public PlatformThread::Delegate {
105 public:
TryLockTestThread(Lock * lock)106 TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
107
ThreadMain()108 virtual void ThreadMain() {
109 got_lock_ = lock_->Try();
110 if (got_lock_)
111 lock_->Unlock();
112 }
113
got_lock() const114 bool got_lock() const { return got_lock_; }
115
116 private:
117 Lock* lock_;
118 bool got_lock_;
119
120 NO_COPY_AND_ASSIGN(TryLockTestThread);
121 };
122
TryLockTest()123 bool TryLockTest() {
124 Lock lock;
125
126 EXPECT_TRUE(lock.Try());
127 // We now have the lock....
128
129 // This thread will not be able to get the lock.
130 {
131 TryLockTestThread thread(&lock);
132 PlatformThreadHandle handle = kNullThreadHandle;
133
134 EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
135
136 PlatformThread::Join(handle);
137
138 EXPECT_FALSE(thread.got_lock());
139 }
140
141 lock.Unlock();
142
143 // This thread will....
144 {
145 TryLockTestThread thread(&lock);
146 PlatformThreadHandle handle = kNullThreadHandle;
147
148 EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
149
150 PlatformThread::Join(handle);
151
152 EXPECT_TRUE(thread.got_lock());
153 // But it released it....
154 EXPECT_TRUE(lock.Try());
155 }
156
157 lock.Unlock();
158 return true;
159 }
160
161 // Tests that locks actually exclude -------------------------------------------
162
163 class MutexLockTestThread : public PlatformThread::Delegate {
164 public:
MutexLockTestThread(Lock * lock,int * value)165 MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
166
167 // Static helper which can also be called from the main thread.
DoStuff(Lock * lock,int * value)168 static void DoStuff(Lock* lock, int* value) {
169 for (int i = 0; i < 40; i++) {
170 lock->Acquire();
171 int v = *value;
172 PlatformThread::Sleep(rand() % 10);
173 *value = v + 1;
174 lock->Unlock();
175 }
176 }
177
ThreadMain()178 virtual void ThreadMain() {
179 DoStuff(lock_, value_);
180 }
181
182 private:
183 Lock* lock_;
184 int* value_;
185
186 NO_COPY_AND_ASSIGN(MutexLockTestThread);
187 };
188
MutexTwoThreads()189 bool MutexTwoThreads() {
190 Lock lock;
191 int value = 0;
192
193 MutexLockTestThread thread(&lock, &value);
194 PlatformThreadHandle handle = kNullThreadHandle;
195
196 EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
197
198 MutexLockTestThread::DoStuff(&lock, &value);
199
200 PlatformThread::Join(handle);
201
202 EXPECT_EQ(2 * 40, value);
203 return true;
204 }
205
MutexFourThreads()206 bool MutexFourThreads() {
207 Lock lock;
208 int value = 0;
209
210 MutexLockTestThread thread1(&lock, &value);
211 MutexLockTestThread thread2(&lock, &value);
212 MutexLockTestThread thread3(&lock, &value);
213 PlatformThreadHandle handle1 = kNullThreadHandle;
214 PlatformThreadHandle handle2 = kNullThreadHandle;
215 PlatformThreadHandle handle3 = kNullThreadHandle;
216
217 EXPECT_TRUE(PlatformThread::Create(&thread1, &handle1));
218 EXPECT_TRUE(PlatformThread::Create(&thread2, &handle2));
219 EXPECT_TRUE(PlatformThread::Create(&thread3, &handle3));
220
221 MutexLockTestThread::DoStuff(&lock, &value);
222
223 PlatformThread::Join(handle1);
224 PlatformThread::Join(handle2);
225 PlatformThread::Join(handle3);
226
227 EXPECT_EQ(4 * 40, value);
228 return true;
229 }
230
231 } // namespace sfntly
232
TEST(LockTest,Basic)233 TEST(LockTest, Basic) {
234 ASSERT_TRUE(sfntly::BasicLockTest());
235 }
236
TEST(LockTest,TryLock)237 TEST(LockTest, TryLock) {
238 ASSERT_TRUE(sfntly::TryLockTest());
239 }
240
TEST(LockTest,Mutex)241 TEST(LockTest, Mutex) {
242 ASSERT_TRUE(sfntly::MutexTwoThreads());
243 ASSERT_TRUE(sfntly::MutexFourThreads());
244 }
245