Chromium Code Reviews| 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 namespace { | |
| 20 | |
| 21 // Death tests misbehave on Android. | |
| 22 #if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) | |
| 23 #define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex) | |
| 24 #else | |
| 25 #define EXPECT_DCHECK_DEATH(statement, regex) | |
|
gab
2016/03/14 18:26:04
Shouldn't this be
#define EXPECT_DCHECK_DEATH(sta
fdoray
2016/03/14 18:55:52
Note that on Posix, the |statement| of EXPECT_DCHE
robliao
2016/03/14 19:09:52
The way we've structured the tests, we expect deat
gab
2016/03/14 19:51:13
Ok, re-lgtm.
PS: Would be nice to confirm that tr
robliao
2016/03/14 19:55:41
From the tests so far, the mobile ones at least do
gab
2016/03/14 20:02:52
I seem to recall a surprising episode on chromium-
robliao
2016/03/14 20:25:07
Sounds good. Feel free to monitor
https://coderevi
robliao
2016/03/14 20:37:13
And the fireworks have started (tests going red),
| |
| 26 #endif | |
| 27 | |
| 28 // Adapted from base::Lock's BasicLockTestThread to make sure | |
| 29 // Acquire()/Release() don't crash. | |
| 30 class BasicLockTestThread : public SimpleThread { | |
| 31 public: | |
| 32 explicit BasicLockTestThread(SchedulerLock* lock) | |
| 33 : SimpleThread("BasicLockTestThread"), | |
| 34 lock_(lock), | |
| 35 acquired_(0) {} | |
| 36 | |
| 37 int acquired() const { return acquired_; } | |
| 38 | |
| 39 private: | |
| 40 void Run() override { | |
| 41 for (int i = 0; i < 10; i++) { | |
| 42 lock_->Acquire(); | |
| 43 acquired_++; | |
| 44 lock_->Release(); | |
| 45 } | |
| 46 for (int i = 0; i < 10; i++) { | |
| 47 lock_->Acquire(); | |
| 48 acquired_++; | |
| 49 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
| 50 lock_->Release(); | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 SchedulerLock* const lock_; | |
| 55 int acquired_; | |
| 56 | |
| 57 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); | |
| 58 }; | |
| 59 | |
| 60 class BasicLockAcquireAndWaitThread : public SimpleThread { | |
| 61 public: | |
| 62 explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock) | |
| 63 : SimpleThread("BasicLockAcquireAndWaitThread"), | |
| 64 lock_(lock), | |
| 65 lock_acquire_event_(false, false), | |
| 66 main_thread_continue_event_(false, false) {} | |
| 67 | |
| 68 void WaitForLockAcquisition() { | |
| 69 lock_acquire_event_.Wait(); | |
| 70 } | |
| 71 | |
| 72 void ContinueMain() { | |
| 73 main_thread_continue_event_.Signal(); | |
| 74 } | |
| 75 | |
| 76 private: | |
| 77 void Run() override { | |
| 78 lock_->Acquire(); | |
| 79 lock_acquire_event_.Signal(); | |
| 80 main_thread_continue_event_.Wait(); | |
| 81 lock_->Release(); | |
| 82 } | |
| 83 | |
| 84 SchedulerLock* const lock_; | |
| 85 WaitableEvent lock_acquire_event_; | |
| 86 WaitableEvent main_thread_continue_event_; | |
| 87 | |
| 88 DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread); | |
| 89 }; | |
| 90 | |
| 91 TEST(TaskSchedulerLock, Basic) { | |
| 92 SchedulerLock lock; | |
| 93 BasicLockTestThread thread(&lock); | |
| 94 | |
| 95 thread.Start(); | |
| 96 | |
| 97 int acquired = 0; | |
| 98 for (int i = 0; i < 5; i++) { | |
| 99 lock.Acquire(); | |
| 100 acquired++; | |
| 101 lock.Release(); | |
| 102 } | |
| 103 for (int i = 0; i < 10; i++) { | |
| 104 lock.Acquire(); | |
| 105 acquired++; | |
| 106 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
| 107 lock.Release(); | |
| 108 } | |
| 109 for (int i = 0; i < 5; i++) { | |
| 110 lock.Acquire(); | |
| 111 acquired++; | |
| 112 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
| 113 lock.Release(); | |
| 114 } | |
| 115 | |
| 116 thread.Join(); | |
| 117 | |
| 118 EXPECT_EQ(acquired, 20); | |
| 119 EXPECT_EQ(thread.acquired(), 20); | |
| 120 } | |
| 121 | |
| 122 TEST(TaskSchedulerLock, AcquirePredecessor) { | |
| 123 SchedulerLock predecessor; | |
| 124 SchedulerLock lock(&predecessor); | |
| 125 predecessor.Acquire(); | |
| 126 lock.Acquire(); | |
| 127 lock.Release(); | |
| 128 predecessor.Release(); | |
| 129 } | |
| 130 | |
| 131 TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) { | |
| 132 SchedulerLock predecessor; | |
| 133 SchedulerLock lock(&predecessor); | |
| 134 EXPECT_DCHECK_DEATH({ | |
| 135 lock.Acquire(); | |
| 136 predecessor.Acquire(); | |
| 137 }, ""); | |
| 138 } | |
| 139 | |
| 140 TEST(TaskSchedulerLock, AcquireNonPredecessor) { | |
| 141 SchedulerLock lock1; | |
| 142 SchedulerLock lock2; | |
| 143 EXPECT_DCHECK_DEATH({ | |
| 144 lock1.Acquire(); | |
| 145 lock2.Acquire(); | |
| 146 }, ""); | |
| 147 } | |
| 148 | |
| 149 TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { | |
| 150 SchedulerLock lock1; | |
| 151 SchedulerLock lock2(&lock1); | |
| 152 SchedulerLock lock3(&lock2); | |
| 153 lock1.Acquire(); | |
| 154 lock2.Acquire(); | |
| 155 lock3.Acquire(); | |
| 156 lock3.Release(); | |
| 157 lock2.Release(); | |
| 158 lock1.Release(); | |
| 159 } | |
| 160 | |
| 161 TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) { | |
| 162 SchedulerLock lock1; | |
| 163 SchedulerLock lock2(&lock1); | |
| 164 SchedulerLock lock3(&lock2); | |
| 165 lock2.Acquire(); | |
| 166 lock3.Acquire(); | |
| 167 lock3.Release(); | |
| 168 lock2.Release(); | |
| 169 } | |
| 170 | |
| 171 TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { | |
| 172 SchedulerLock lock1; | |
| 173 SchedulerLock lock2(&lock1); | |
| 174 SchedulerLock lock3(&lock2); | |
| 175 EXPECT_DCHECK_DEATH({ | |
| 176 lock1.Acquire(); | |
| 177 lock3.Acquire(); | |
| 178 }, ""); | |
| 179 } | |
| 180 | |
| 181 TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { | |
| 182 SchedulerLock lock1; | |
| 183 SchedulerLock lock2; | |
| 184 BasicLockAcquireAndWaitThread thread(&lock1); | |
| 185 thread.Start(); | |
| 186 | |
| 187 lock2.Acquire(); | |
| 188 thread.WaitForLockAcquisition(); | |
| 189 thread.ContinueMain(); | |
| 190 thread.Join(); | |
| 191 lock2.Release(); | |
| 192 } | |
| 193 | |
| 194 TEST(TaskSchedulerLock, | |
| 195 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) { | |
| 196 // A lock and its predecessor may be safely acquired on different threads. | |
| 197 // This Thread Other Thread | |
| 198 // predecessor.Acquire() | |
| 199 // lock.Acquire() | |
| 200 // predecessor.Release() | |
| 201 // lock.Release() | |
| 202 SchedulerLock predecessor; | |
| 203 SchedulerLock lock(&predecessor); | |
| 204 predecessor.Acquire(); | |
| 205 BasicLockAcquireAndWaitThread thread(&lock); | |
| 206 thread.Start(); | |
| 207 thread.WaitForLockAcquisition(); | |
| 208 predecessor.Release(); | |
| 209 thread.ContinueMain(); | |
| 210 thread.Join(); | |
| 211 } | |
| 212 | |
| 213 TEST(TaskSchedulerLock, | |
| 214 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) { | |
| 215 // A lock and its predecessor may be safely acquired on different threads. | |
| 216 // This Thread Other Thread | |
| 217 // lock.Acquire() | |
| 218 // predecessor.Acquire() | |
| 219 // lock.Release() | |
| 220 // predecessor.Release() | |
| 221 SchedulerLock predecessor; | |
| 222 SchedulerLock lock(&predecessor); | |
| 223 lock.Acquire(); | |
| 224 BasicLockAcquireAndWaitThread thread(&predecessor); | |
| 225 thread.Start(); | |
| 226 thread.WaitForLockAcquisition(); | |
| 227 lock.Release(); | |
| 228 thread.ContinueMain(); | |
| 229 thread.Join(); | |
| 230 } | |
| 231 | |
| 232 TEST(TaskSchedulerLock, | |
| 233 AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference) { | |
| 234 // Acquisition of an unrelated lock on another thread should not affect a | |
| 235 // legal lock acquisition with a predecessor on this thread. | |
| 236 // This Thread Other Thread | |
| 237 // predecessor.Acquire() | |
| 238 // unrelated.Acquire() | |
| 239 // lock.Acquire() | |
| 240 // unrelated.Release() | |
| 241 // lock.Release() | |
| 242 // predecessor.Release(); | |
| 243 SchedulerLock predecessor; | |
| 244 SchedulerLock lock(&predecessor); | |
| 245 predecessor.Acquire(); | |
| 246 SchedulerLock unrelated; | |
| 247 BasicLockAcquireAndWaitThread thread(&unrelated); | |
| 248 thread.Start(); | |
| 249 thread.WaitForLockAcquisition(); | |
| 250 lock.Acquire(); | |
| 251 thread.ContinueMain(); | |
| 252 thread.Join(); | |
| 253 lock.Release(); | |
| 254 predecessor.Release(); | |
| 255 } | |
| 256 | |
| 257 TEST(TaskSchedulerLock, SelfReferentialLock) { | |
| 258 struct SelfReferentialLock { | |
| 259 SelfReferentialLock() : lock(&lock) {} | |
| 260 | |
| 261 SchedulerLock lock; | |
| 262 }; | |
| 263 | |
| 264 EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }, ""); | |
| 265 } | |
| 266 | |
| 267 TEST(TaskSchedulerLock, PredecessorCycle) { | |
| 268 struct LockCycle { | |
| 269 LockCycle() : lock1(&lock2), lock2(&lock1) {} | |
| 270 | |
| 271 SchedulerLock lock1; | |
| 272 SchedulerLock lock2; | |
| 273 }; | |
| 274 | |
| 275 EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); | |
| 276 } | |
| 277 | |
| 278 TEST(TaskSchedulerLock, PredecessorLongerCycle) { | |
| 279 struct LockCycle { | |
| 280 LockCycle() | |
| 281 : lock1(&lock5), | |
| 282 lock2(&lock1), | |
| 283 lock3(&lock2), | |
| 284 lock4(&lock3), | |
| 285 lock5(&lock4) {} | |
| 286 | |
| 287 SchedulerLock lock1; | |
| 288 SchedulerLock lock2; | |
| 289 SchedulerLock lock3; | |
| 290 SchedulerLock lock4; | |
| 291 SchedulerLock lock5; | |
| 292 }; | |
| 293 | |
| 294 EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); | |
| 295 } | |
| 296 | |
| 297 } // namespace | |
| 298 } // namespace internal | |
| 299 } // namespace base | |
| OLD | NEW |