OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "rlz/lib/recursive_lock.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include "base/compiler_specific.h" | |
10 #include "base/threading/platform_thread.h" | |
11 #include "base/time.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 using base::kNullThreadHandle; | |
15 using base::PlatformThread; | |
16 using base::PlatformThreadHandle; | |
17 using base::TimeDelta; | |
18 | |
19 namespace rlz_lib { | |
20 | |
21 // Basic test to make sure that Acquire()/Release() don't crash. | |
22 class BasicLockTestThread : public PlatformThread::Delegate { | |
23 public: | |
24 BasicLockTestThread(RecursiveLock* lock) : lock_(lock), acquired_(0) {} | |
25 | |
26 virtual void ThreadMain() OVERRIDE { | |
27 for (int i = 0; i < 10; i++) { | |
28 lock_->Acquire(); | |
29 acquired_++; | |
30 lock_->Release(); | |
31 } | |
32 for (int i = 0; i < 10; i++) { | |
33 lock_->Acquire(); | |
34 acquired_++; | |
35 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
36 lock_->Release(); | |
37 } | |
38 } | |
39 | |
40 int acquired() const { return acquired_; } | |
41 | |
42 private: | |
43 RecursiveLock* lock_; | |
44 int acquired_; | |
45 | |
46 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); | |
47 }; | |
48 | |
49 TEST(RecursiveLockTest, Basic) { | |
50 RecursiveLock lock; | |
51 BasicLockTestThread thread(&lock); | |
52 PlatformThreadHandle handle = kNullThreadHandle; | |
53 | |
54 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
55 | |
56 int acquired = 0; | |
57 for (int i = 0; i < 5; i++) { | |
58 lock.Acquire(); | |
59 acquired++; | |
60 lock.Release(); | |
61 } | |
62 for (int i = 0; i < 10; i++) { | |
63 lock.Acquire(); | |
64 acquired++; | |
65 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
66 lock.Release(); | |
67 } | |
68 for (int i = 0; i < 5; i++) { | |
69 lock.Acquire(); | |
70 acquired++; | |
71 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
72 lock.Release(); | |
73 } | |
74 | |
75 PlatformThread::Join(handle); | |
76 | |
77 EXPECT_EQ(acquired, 20); | |
78 EXPECT_EQ(thread.acquired(), 20); | |
79 } | |
80 | |
81 // Tests that locks are actually exclusive. | |
82 class MutexLockTestThread : public PlatformThread::Delegate { | |
83 public: | |
84 MutexLockTestThread(RecursiveLock* lock, int* value) | |
85 : lock_(lock), | |
86 value_(value) { | |
87 } | |
88 | |
89 // Static helper which can also be called from the main thread. | |
90 static void DoStuff(RecursiveLock* lock, int* value) { | |
91 for (int i = 0; i < 40; i++) { | |
92 lock->Acquire(); | |
93 int v = *value; | |
94 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); | |
95 *value = v + 1; | |
96 lock->Release(); | |
97 } | |
98 } | |
99 | |
100 virtual void ThreadMain() OVERRIDE { | |
101 DoStuff(lock_, value_); | |
102 } | |
103 | |
104 private: | |
105 RecursiveLock* lock_; | |
106 int* value_; | |
107 | |
108 DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread); | |
109 }; | |
110 | |
111 TEST(RecursiveLockTest, MutexTwoThreads) { | |
112 RecursiveLock lock; | |
113 int value = 0; | |
114 | |
115 MutexLockTestThread thread(&lock, &value); | |
116 PlatformThreadHandle handle = kNullThreadHandle; | |
117 | |
118 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
119 | |
120 MutexLockTestThread::DoStuff(&lock, &value); | |
121 | |
122 PlatformThread::Join(handle); | |
123 | |
124 EXPECT_EQ(2 * 40, value); | |
125 } | |
126 | |
127 TEST(RecursiveLockTest, MutexFourThreads) { | |
128 RecursiveLock lock; | |
129 int value = 0; | |
130 | |
131 MutexLockTestThread thread1(&lock, &value); | |
132 MutexLockTestThread thread2(&lock, &value); | |
133 MutexLockTestThread thread3(&lock, &value); | |
134 PlatformThreadHandle handle1 = kNullThreadHandle; | |
135 PlatformThreadHandle handle2 = kNullThreadHandle; | |
136 PlatformThreadHandle handle3 = kNullThreadHandle; | |
137 | |
138 ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); | |
139 ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); | |
140 ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3)); | |
141 | |
142 MutexLockTestThread::DoStuff(&lock, &value); | |
143 | |
144 PlatformThread::Join(handle1); | |
145 PlatformThread::Join(handle2); | |
146 PlatformThread::Join(handle3); | |
147 | |
148 EXPECT_EQ(4 * 40, value); | |
149 } | |
150 | |
151 // Tests that locks are recursive. | |
152 class MutexRecursiveLockTestThread : public PlatformThread::Delegate { | |
153 public: | |
154 MutexRecursiveLockTestThread(RecursiveLock* lock, int* value) | |
155 : lock_(lock), | |
156 value_(value) { | |
157 } | |
158 | |
159 // Static helper which can also be called from the main thread. | |
160 static void DoStuff(RecursiveLock* lock, int* value) { | |
161 for (int i = 0; i < 20; i++) { | |
162 // First lock. | |
163 lock->Acquire(); | |
164 int v = *value; | |
165 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); | |
166 *value = v + 1; | |
167 { | |
168 // Recursive lock. | |
169 lock->Acquire(); | |
170 int v = *value; | |
171 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); | |
172 *value = v + 1; | |
173 lock->Release(); | |
174 } | |
175 v = *value; | |
176 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); | |
177 *value = v + 1; | |
178 lock->Release(); | |
179 } | |
180 } | |
181 | |
182 virtual void ThreadMain() OVERRIDE { | |
183 DoStuff(lock_, value_); | |
184 } | |
185 | |
186 private: | |
187 RecursiveLock* lock_; | |
188 int* value_; | |
189 | |
190 DISALLOW_COPY_AND_ASSIGN(MutexRecursiveLockTestThread); | |
191 }; | |
192 | |
193 | |
194 TEST(RecursiveLockTest, MutexTwoThreadsRecursive) { | |
195 RecursiveLock lock; | |
196 int value = 0; | |
197 | |
198 MutexRecursiveLockTestThread thread(&lock, &value); | |
199 PlatformThreadHandle handle = kNullThreadHandle; | |
200 | |
201 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
202 | |
203 MutexRecursiveLockTestThread::DoStuff(&lock, &value); | |
204 | |
205 PlatformThread::Join(handle); | |
206 | |
207 EXPECT_EQ(2 * 60, value); | |
208 } | |
209 | |
210 TEST(RecursiveLockTest, MutexFourThreadsRecursive) { | |
211 RecursiveLock lock; | |
212 int value = 0; | |
213 | |
214 MutexRecursiveLockTestThread thread1(&lock, &value); | |
215 MutexRecursiveLockTestThread thread2(&lock, &value); | |
216 MutexRecursiveLockTestThread thread3(&lock, &value); | |
217 PlatformThreadHandle handle1 = kNullThreadHandle; | |
218 PlatformThreadHandle handle2 = kNullThreadHandle; | |
219 PlatformThreadHandle handle3 = kNullThreadHandle; | |
220 | |
221 ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); | |
222 ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); | |
223 ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3)); | |
224 | |
225 MutexRecursiveLockTestThread::DoStuff(&lock, &value); | |
226 | |
227 PlatformThread::Join(handle1); | |
228 PlatformThread::Join(handle2); | |
229 PlatformThread::Join(handle3); | |
230 | |
231 EXPECT_EQ(4 * 60, value); | |
232 } | |
233 | |
234 } // namespace rlz_lib | |
OLD | NEW |