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 "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace base { | |
17 namespace internal { | |
18 | |
19 // Adapted from base::Lock's BasicLockTestThread to make sure | |
20 // Acquire()/Release() don't crash. | |
21 class BasicLockTestThread : public PlatformThread::Delegate { | |
22 public: | |
23 explicit BasicLockTestThread(SchedulerLock* lock) | |
24 : lock_(lock), | |
25 acquired_(0) {} | |
26 | |
27 void ThreadMain() override { | |
28 for (int i = 0; i < 10; i++) { | |
29 lock_->Acquire(); | |
30 acquired_++; | |
31 lock_->Release(); | |
32 } | |
33 for (int i = 0; i < 10; i++) { | |
34 lock_->Acquire(); | |
35 acquired_++; | |
36 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
37 lock_->Release(); | |
38 } | |
39 } | |
40 | |
41 int acquired() const { return acquired_; } | |
42 | |
43 private: | |
44 SchedulerLock* const lock_; | |
45 int acquired_; | |
46 | |
47 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); | |
48 }; | |
49 | |
50 class BasicLockAcquireAndWaitThread : public PlatformThread::Delegate { | |
51 public: | |
52 explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock) | |
53 : lock_(lock), | |
54 lock_acquire_event_(false, false), | |
55 main_thread_continue_event_(false, false) {} | |
56 | |
57 void ThreadMain() override { | |
58 lock_->Acquire(); | |
59 lock_acquire_event_.Signal(); | |
60 main_thread_continue_event_.Wait(); | |
61 lock_->Release(); | |
62 } | |
63 | |
64 void WaitForLockAcquisition() { | |
65 lock_acquire_event_.Wait(); | |
66 } | |
67 | |
68 void ContinueMain() { | |
69 main_thread_continue_event_.Signal(); | |
70 } | |
71 | |
72 private: | |
73 SchedulerLock* const lock_; | |
74 WaitableEvent lock_acquire_event_; | |
75 WaitableEvent main_thread_continue_event_; | |
76 | |
77 DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread); | |
78 }; | |
79 | |
80 TEST(TaskSchedulerLock, Basic) { | |
81 SchedulerLock lock; | |
82 BasicLockTestThread thread(&lock); | |
83 PlatformThreadHandle handle; | |
84 | |
85 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
86 | |
87 int acquired = 0; | |
88 for (int i = 0; i < 5; i++) { | |
89 lock.Acquire(); | |
90 acquired++; | |
91 lock.Release(); | |
92 } | |
93 for (int i = 0; i < 10; i++) { | |
94 lock.Acquire(); | |
95 acquired++; | |
96 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
97 lock.Release(); | |
98 } | |
99 for (int i = 0; i < 5; i++) { | |
100 lock.Acquire(); | |
101 acquired++; | |
102 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); | |
103 lock.Release(); | |
104 } | |
105 | |
106 PlatformThread::Join(handle); | |
107 | |
108 EXPECT_EQ(acquired, 20); | |
109 EXPECT_EQ(thread.acquired(), 20); | |
110 } | |
111 | |
112 TEST(TaskSchedulerLock, AcquirePredecessor) { | |
113 SchedulerLock predecessor; | |
114 SchedulerLock lock(&predecessor); | |
115 predecessor.Acquire(); | |
116 lock.Acquire(); | |
117 lock.Release(); | |
118 predecessor.Release(); | |
119 } | |
120 | |
121 TEST(TaskSchedulerLock, AcquireNonPredecessor) { | |
122 SchedulerLock lock1; | |
123 SchedulerLock lock2; | |
124 EXPECT_DEBUG_DEATH({ | |
125 lock1.Acquire(); | |
126 lock2.Acquire(); | |
127 }, ""); | |
128 } | |
129 | |
130 TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { | |
131 SchedulerLock lock1; | |
132 SchedulerLock lock2(&lock1); | |
133 SchedulerLock lock3(&lock2); | |
134 lock1.Acquire(); | |
135 lock2.Acquire(); | |
136 lock3.Acquire(); | |
137 lock3.Release(); | |
138 lock2.Release(); | |
139 lock1.Release(); | |
140 } | |
141 | |
142 TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) { | |
143 SchedulerLock lock1; | |
144 SchedulerLock lock2(&lock1); | |
145 SchedulerLock lock3(&lock2); | |
146 lock2.Acquire(); | |
147 lock3.Acquire(); | |
148 lock3.Release(); | |
149 lock2.Release(); | |
150 } | |
151 | |
152 TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { | |
153 SchedulerLock lock1; | |
154 SchedulerLock lock2(&lock1); | |
155 SchedulerLock lock3(&lock2); | |
156 EXPECT_DEBUG_DEATH({ | |
157 lock1.Acquire(); | |
158 lock3.Acquire(); | |
159 }, ""); | |
160 } | |
161 | |
162 TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { | |
163 SchedulerLock lock1; | |
164 SchedulerLock lock2; | |
165 BasicLockAcquireAndWaitThread thread(&lock1); | |
166 PlatformThreadHandle handle; | |
167 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
168 | |
169 lock2.Acquire(); | |
170 thread.WaitForLockAcquisition(); | |
171 thread.ContinueMain(); | |
172 PlatformThread::Join(handle); | |
173 lock2.Release(); | |
174 } | |
gab
2016/02/19 22:05:24
What is this now testing that the next two tests a
robliao
2016/02/19 23:51:12
This tests the absence of any predecessor relation
| |
175 | |
176 TEST(TaskSchedulerLock, | |
177 AcquireLocksWithPredecessorDifferentThreadsSafely1PredecessorFirst) { | |
178 // A lock and its predecessor may be safely acquired on different threads. | |
179 // This Thread Other Thread | |
180 // predecessor.Acquire() | |
181 // lock.Acquire() | |
182 // predecessor.Release() | |
183 // lock.Release() | |
184 SchedulerLock predecessor; | |
185 SchedulerLock lock(&predecessor); | |
186 predecessor.Acquire(); | |
187 BasicLockAcquireAndWaitThread thread(&lock); | |
188 PlatformThreadHandle handle; | |
189 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
190 thread.WaitForLockAcquisition(); | |
191 predecessor.Release(); | |
192 thread.ContinueMain(); | |
193 PlatformThread::Join(handle); | |
194 } | |
195 | |
196 TEST(TaskSchedulerLock, | |
197 AcquireLocksWithPredecessorDifferentThreadsSafely1PredecessorLast) { | |
198 // A lock and its predecessor may be safely acquired on different threads. | |
199 // This Thread Other Thread | |
200 // lock.Acquire() | |
201 // predecessor.Acquire() | |
202 // lock.Release() | |
203 // predecessor.Release() | |
204 SchedulerLock predecessor; | |
205 SchedulerLock lock(&predecessor); | |
206 lock.Acquire(); | |
207 BasicLockAcquireAndWaitThread thread(&predecessor); | |
208 PlatformThreadHandle handle; | |
209 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | |
210 thread.WaitForLockAcquisition(); | |
211 lock.Release(); | |
212 thread.ContinueMain(); | |
213 PlatformThread::Join(handle); | |
214 } | |
215 | |
216 TEST(TaskSchedulerLock, SelfReferentialLock) { | |
217 struct SelfReferentialLock { | |
218 SelfReferentialLock() : lock(&lock) {} | |
219 | |
220 SchedulerLock lock; | |
221 }; | |
222 | |
223 EXPECT_DEBUG_DEATH({ SelfReferentialLock lock; }, ""); | |
224 } | |
225 | |
226 TEST(TaskSchedulerLock, PredecessorCycle) { | |
227 struct LockCycle { | |
228 LockCycle() : lock1(&lock2), lock2(&lock1) {} | |
229 | |
230 SchedulerLock lock1; | |
231 SchedulerLock lock2; | |
232 }; | |
233 | |
234 EXPECT_DEBUG_DEATH({ LockCycle cycle; }, ""); | |
235 } | |
236 | |
237 TEST(TaskSchedulerLock, PredecessorLongerCycle) { | |
238 struct LockCycle { | |
239 LockCycle() | |
240 : lock1(&lock5), | |
241 lock2(&lock1), | |
242 lock3(&lock2), | |
243 lock4(&lock3), | |
244 lock5(&lock4) {} | |
245 | |
246 SchedulerLock lock1; | |
247 SchedulerLock lock2; | |
248 SchedulerLock lock3; | |
249 SchedulerLock lock4; | |
250 SchedulerLock lock5; | |
251 }; | |
252 | |
253 EXPECT_DEBUG_DEATH({ LockCycle cycle; }, ""); | |
254 } | |
255 | |
256 } // namespace internal | |
257 } // base | |
OLD | NEW |