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 | |
|
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 |