OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "base/task_scheduler/scheduler_lock.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include "base/compiler_specific.h" | |
10 #include "base/macros.h" | |
11 #include "base/rand_util.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "base/threading/platform_thread.h" | |
14 #include "base/threading/simple_thread.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace base { | |
18 namespace internal { | |
19 | |
danakj
2016/03/08 21:24:50
Oh, can you wrap the whole test file in a nested a
robliao
2016/03/08 22:14:08
Done.
| |
20 // Adapted from base::Lock's BasicLockTestThread to make sure | |
21 // Acquire()/Release() don't crash. | |
22 class BasicLockTestThread : public SimpleThread { | |
23 public: | |
24 explicit BasicLockTestThread(SchedulerLock* lock) | |
25 : SimpleThread("BasicLockTestThread"), | |
26 lock_(lock), | |
27 acquired_(0) {} | |
28 | |
29 int acquired() const { return acquired_; } | |
30 | |
31 private: | |
32 void Run() override { | |
33 for (int i = 0; i < 10; i++) { | |
34 lock_->Acquire(); | |
35 acquired_++; | |
36 lock_->Release(); | |
37 } | |
38 for (int i = 0; i < 10; i++) { | |
39 lock_->Acquire(); | |
40 acquired_++; | |
41 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
42 lock_->Release(); | |
43 } | |
44 } | |
45 | |
46 SchedulerLock* const lock_; | |
47 int acquired_; | |
48 | |
49 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); | |
50 }; | |
51 | |
52 class BasicLockAcquireAndWaitThread : public SimpleThread { | |
53 public: | |
54 explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock) | |
55 : SimpleThread("BasicLockAcquireAndWaitThread"), | |
56 lock_(lock), | |
57 lock_acquire_event_(false, false), | |
58 main_thread_continue_event_(false, false) {} | |
59 | |
60 void WaitForLockAcquisition() { | |
61 lock_acquire_event_.Wait(); | |
62 } | |
63 | |
64 void ContinueMain() { | |
65 main_thread_continue_event_.Signal(); | |
66 } | |
67 | |
68 private: | |
69 void Run() override { | |
70 lock_->Acquire(); | |
71 lock_acquire_event_.Signal(); | |
72 main_thread_continue_event_.Wait(); | |
73 lock_->Release(); | |
74 } | |
75 | |
76 SchedulerLock* const lock_; | |
77 WaitableEvent lock_acquire_event_; | |
78 WaitableEvent main_thread_continue_event_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread); | |
81 }; | |
82 | |
83 TEST(TaskSchedulerLock, Basic) { | |
84 SchedulerLock lock; | |
85 BasicLockTestThread thread(&lock); | |
86 | |
87 thread.Start(); | |
88 | |
89 int acquired = 0; | |
90 for (int i = 0; i < 5; i++) { | |
91 lock.Acquire(); | |
92 acquired++; | |
93 lock.Release(); | |
94 } | |
95 for (int i = 0; i < 10; i++) { | |
96 lock.Acquire(); | |
97 acquired++; | |
98 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
danakj
2016/03/08 21:22:56
Why is it base::RandInt(0, 19) above but rand() %
robliao
2016/03/08 22:14:08
Incomplete migration from the original lock unitte
| |
99 lock.Release(); | |
100 } | |
101 for (int i = 0; i < 5; i++) { | |
102 lock.Acquire(); | |
103 acquired++; | |
104 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
105 lock.Release(); | |
106 } | |
107 | |
108 thread.Join(); | |
109 | |
110 EXPECT_EQ(acquired, 20); | |
111 EXPECT_EQ(thread.acquired(), 20); | |
112 } | |
113 | |
114 TEST(TaskSchedulerLock, AcquirePredecessor) { | |
115 SchedulerLock predecessor; | |
116 SchedulerLock lock(&predecessor); | |
117 predecessor.Acquire(); | |
118 lock.Acquire(); | |
119 lock.Release(); | |
120 predecessor.Release(); | |
121 } | |
122 | |
123 TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) { | |
124 SchedulerLock predecessor; | |
125 SchedulerLock lock(&predecessor); | |
126 EXPECT_DEBUG_DEATH({ | |
danakj
2016/03/08 21:22:56
EXPECT_DEBUG_DEATH asserts that the given statemen
robliao
2016/03/08 22:14:08
Changed to
#if DCHECK_IS_ON()
#define EXPECT_DCHEC
| |
127 lock.Acquire(); | |
128 predecessor.Acquire(); | |
129 }, ""); | |
130 } | |
131 | |
132 TEST(TaskSchedulerLock, AcquireNonPredecessor) { | |
133 SchedulerLock lock1; | |
134 SchedulerLock lock2; | |
135 EXPECT_DEBUG_DEATH({ | |
136 lock1.Acquire(); | |
137 lock2.Acquire(); | |
138 }, ""); | |
139 } | |
140 | |
141 TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { | |
142 SchedulerLock lock1; | |
143 SchedulerLock lock2(&lock1); | |
144 SchedulerLock lock3(&lock2); | |
145 lock1.Acquire(); | |
146 lock2.Acquire(); | |
147 lock3.Acquire(); | |
148 lock3.Release(); | |
149 lock2.Release(); | |
150 lock1.Release(); | |
151 } | |
152 | |
153 TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) { | |
154 SchedulerLock lock1; | |
155 SchedulerLock lock2(&lock1); | |
156 SchedulerLock lock3(&lock2); | |
157 lock2.Acquire(); | |
158 lock3.Acquire(); | |
159 lock3.Release(); | |
160 lock2.Release(); | |
161 } | |
162 | |
163 TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { | |
164 SchedulerLock lock1; | |
165 SchedulerLock lock2(&lock1); | |
166 SchedulerLock lock3(&lock2); | |
167 EXPECT_DEBUG_DEATH({ | |
168 lock1.Acquire(); | |
169 lock3.Acquire(); | |
170 }, ""); | |
171 } | |
172 | |
173 TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { | |
174 SchedulerLock lock1; | |
175 SchedulerLock lock2; | |
176 BasicLockAcquireAndWaitThread thread(&lock1); | |
177 thread.Start(); | |
178 | |
179 lock2.Acquire(); | |
180 thread.WaitForLockAcquisition(); | |
181 thread.ContinueMain(); | |
182 thread.Join(); | |
183 lock2.Release(); | |
184 } | |
185 | |
186 TEST(TaskSchedulerLock, | |
187 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) { | |
188 // A lock and its predecessor may be safely acquired on different threads. | |
189 // This Thread Other Thread | |
190 // predecessor.Acquire() | |
191 // lock.Acquire() | |
192 // predecessor.Release() | |
193 // lock.Release() | |
194 SchedulerLock predecessor; | |
195 SchedulerLock lock(&predecessor); | |
196 predecessor.Acquire(); | |
197 BasicLockAcquireAndWaitThread thread(&lock); | |
198 thread.Start(); | |
199 thread.WaitForLockAcquisition(); | |
200 predecessor.Release(); | |
201 thread.ContinueMain(); | |
202 thread.Join(); | |
203 } | |
204 | |
205 TEST(TaskSchedulerLock, | |
206 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) { | |
danakj
2016/03/08 21:22:56
One more test case worth mentioning maybe?
This t
robliao
2016/03/08 22:14:08
I'll buy that. Added a case.
| |
207 // A lock and its predecessor may be safely acquired on different threads. | |
208 // This Thread Other Thread | |
209 // lock.Acquire() | |
210 // predecessor.Acquire() | |
211 // lock.Release() | |
212 // predecessor.Release() | |
213 SchedulerLock predecessor; | |
214 SchedulerLock lock(&predecessor); | |
215 lock.Acquire(); | |
216 BasicLockAcquireAndWaitThread thread(&predecessor); | |
217 thread.Start(); | |
218 thread.WaitForLockAcquisition(); | |
219 lock.Release(); | |
220 thread.ContinueMain(); | |
221 thread.Join(); | |
222 } | |
223 | |
224 TEST(TaskSchedulerLock, SelfReferentialLock) { | |
225 struct SelfReferentialLock { | |
226 SelfReferentialLock() : lock(&lock) {} | |
227 | |
228 SchedulerLock lock; | |
229 }; | |
230 | |
231 EXPECT_DEBUG_DEATH({ SelfReferentialLock lock; }, ""); | |
232 } | |
233 | |
234 TEST(TaskSchedulerLock, PredecessorCycle) { | |
235 struct LockCycle { | |
236 LockCycle() : lock1(&lock2), lock2(&lock1) {} | |
237 | |
238 SchedulerLock lock1; | |
239 SchedulerLock lock2; | |
240 }; | |
241 | |
242 EXPECT_DEBUG_DEATH({ LockCycle cycle; }, ""); | |
243 } | |
244 | |
245 TEST(TaskSchedulerLock, PredecessorLongerCycle) { | |
246 struct LockCycle { | |
247 LockCycle() | |
248 : lock1(&lock5), | |
249 lock2(&lock1), | |
250 lock3(&lock2), | |
251 lock4(&lock3), | |
252 lock5(&lock4) {} | |
253 | |
254 SchedulerLock lock1; | |
255 SchedulerLock lock2; | |
256 SchedulerLock lock3; | |
257 SchedulerLock lock4; | |
258 SchedulerLock lock5; | |
259 }; | |
260 | |
261 EXPECT_DEBUG_DEATH({ LockCycle cycle; }, ""); | |
262 } | |
263 | |
264 } // namespace internal | |
265 } // base | |
OLD | NEW |