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_impl.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <unordered_map> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/singleton.h" | |
| 13 #include "base/synchronization/condition_variable.h" | |
| 14 #include "base/threading/platform_thread.h" | |
| 15 | |
| 16 namespace base { | |
| 17 namespace internal { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 class SafeAcquisitionTracker { | |
| 22 public: | |
| 23 static SafeAcquisitionTracker* GetInstance() { | |
| 24 return base::Singleton<SafeAcquisitionTracker>::get(); | |
|
gab
2016/02/18 16:58:06
Instead of a Singleton, can we use a LazyInstance:
robliao
2016/02/18 21:59:37
Works for me. Done.
| |
| 25 } | |
| 26 | |
| 27 void RegisterLock( | |
| 28 const SchedulerLockImpl* const lock, | |
| 29 const SchedulerLockImpl* const predecessor) { | |
| 30 // Reentrant locks are unexpected. | |
|
gab
2016/02/18 16:58:06
s/unexpected/unsupported/
robliao
2016/02/18 21:59:37
Done.
| |
| 31 CHECK(lock != predecessor); | |
|
gab
2016/02/18 16:58:06
DCHECK
(equivalent since this code ever runs in
robliao
2016/02/18 21:59:37
Done.
| |
| 32 AutoLock auto_lock(metadata_lock_); | |
| 33 allowed_predecessors_[lock] = predecessor; | |
| 34 AssertSafePredecessor(lock); | |
| 35 } | |
| 36 | |
| 37 void UnregisterLock(const SchedulerLockImpl* const lock) { | |
| 38 AutoLock auto_lock(metadata_lock_); | |
| 39 allowed_predecessors_.erase(lock); | |
| 40 } | |
| 41 | |
| 42 void RecordAcquisition(const SchedulerLockImpl* const lock) { | |
| 43 AutoLock auto_lock(metadata_lock_); | |
| 44 const PlatformThreadId id = PlatformThread::CurrentId(); | |
| 45 AssertSafeAcquire(id, lock); | |
| 46 LockVector& thread_locks = acquired_locks_[id]; | |
| 47 thread_locks.push_back(lock); | |
|
gab
2016/02/18 16:58:06
Merge above two lines into:
acquired_locks_[id].p
robliao
2016/02/18 21:59:37
Symmetry is nice, but it's still the same code. Me
| |
| 48 } | |
| 49 | |
| 50 void RecordRelease(const SchedulerLockImpl* const lock) { | |
| 51 AutoLock auto_lock(metadata_lock_); | |
| 52 const PlatformThreadId id = PlatformThread::CurrentId(); | |
| 53 LockVector& thread_locks = acquired_locks_[id]; | |
| 54 const auto iter = | |
| 55 std::find(thread_locks.begin(), thread_locks.end(), lock); | |
| 56 DCHECK(iter != thread_locks.end()); | |
| 57 thread_locks.erase(iter); | |
| 58 } | |
| 59 | |
| 60 private: | |
| 61 friend struct base::DefaultSingletonTraits<SafeAcquisitionTracker>; | |
| 62 using LockVector = std::vector<const SchedulerLockImpl*>; | |
| 63 using PredecessorMap = std::unordered_map< | |
| 64 const SchedulerLockImpl*, const SchedulerLockImpl*>; | |
| 65 using AcquisitionMap = | |
| 66 std::unordered_map<base::PlatformThreadId, LockVector>; | |
|
gab
2016/02/18 16:58:06
How about using ThreadLocalStorage here instead of
robliao
2016/02/18 21:59:37
We would only be able to save on the release. Acqu
gab
2016/02/19 16:08:02
To avoid this being a "gotcha -- only lock here no
gab
2016/02/19 22:05:24
ping ^^
robliao
2016/02/19 23:51:11
Oops. Missed this one. Done.
| |
| 67 | |
| 68 SafeAcquisitionTracker() = default; | |
| 69 | |
| 70 void AssertSafeAcquire(PlatformThreadId id, | |
|
gab
2016/02/18 16:58:06
Add a comment + mention that this must be called b
robliao
2016/02/18 21:59:37
This keeps both RecordAcquisition and RecordReleas
| |
| 71 const SchedulerLockImpl* const lock) { | |
| 72 metadata_lock_.AssertAcquired(); | |
| 73 const LockVector& thread_locks = acquired_locks_[id]; | |
| 74 | |
| 75 // If the thread hasn't ever acquired a lock, this is inherently safe. | |
|
gab
2016/02/18 16:58:06
// If the thread doesn't currently own a lock, thi
robliao
2016/02/18 21:59:37
Fixed.
| |
| 76 if (thread_locks.empty()) | |
| 77 return; | |
| 78 | |
| 79 // Otherwise, make sure that the previous lock acquired is an allowed | |
| 80 // predecessor. | |
| 81 const SchedulerLockImpl* allowed_predecessor = | |
| 82 allowed_predecessors_[lock]; | |
| 83 DCHECK(thread_locks.back() == allowed_predecessor); | |
| 84 } | |
| 85 | |
| 86 void AssertSafePredecessor(const SchedulerLockImpl* lock) { | |
| 87 metadata_lock_.AssertAcquired(); | |
| 88 for (const SchedulerLockImpl* predecessor = allowed_predecessors_[lock]; | |
| 89 predecessor != nullptr; | |
| 90 predecessor = allowed_predecessors_[predecessor]) { | |
| 91 if (predecessor == lock) | |
| 92 NOTREACHED(); | |
|
gab
2016/02/18 16:58:06
So is this method only verifying that we do not ge
robliao
2016/02/18 21:59:37
There's actually a unit test for this :-). It is i
| |
| 93 } | |
| 94 } | |
| 95 | |
| 96 // Synchronizes everything in SafeAcquisitionTracker. | |
| 97 base::Lock metadata_lock_; | |
| 98 | |
| 99 PredecessorMap allowed_predecessors_; | |
|
gab
2016/02/18 16:58:07
Whenever I saw this in code the plural form made m
robliao
2016/02/18 21:59:37
Went with allowed_predecessor_map.
| |
| 100 AcquisitionMap acquired_locks_; | |
| 101 | |
| 102 DISALLOW_COPY_AND_ASSIGN(SafeAcquisitionTracker); | |
| 103 }; | |
| 104 | |
| 105 } // namespace | |
| 106 | |
| 107 SchedulerLockImpl::SchedulerLockImpl() : SchedulerLockImpl(nullptr) {} | |
|
gab
2016/02/18 16:58:06
Seems this will call RegisterLock with a nullptr p
robliao
2016/02/18 21:59:37
In invariant here is that all locks are registered
| |
| 108 | |
| 109 SchedulerLockImpl::SchedulerLockImpl(const SchedulerLockImpl* predecessor) { | |
| 110 SafeAcquisitionTracker::GetInstance()->RegisterLock(this, predecessor); | |
| 111 } | |
| 112 | |
| 113 SchedulerLockImpl::~SchedulerLockImpl() { | |
| 114 SafeAcquisitionTracker::GetInstance()->UnregisterLock(this); | |
| 115 } | |
| 116 | |
| 117 void SchedulerLockImpl::Acquire() { | |
| 118 lock_.Acquire(); | |
| 119 SafeAcquisitionTracker::GetInstance()->RecordAcquisition(this); | |
| 120 } | |
| 121 | |
| 122 void SchedulerLockImpl::Release() { | |
| 123 lock_.Release(); | |
| 124 SafeAcquisitionTracker::GetInstance()->RecordRelease(this); | |
| 125 } | |
| 126 | |
| 127 scoped_ptr<ConditionVariable> SchedulerLockImpl::CreateConditionVariable() { | |
| 128 return scoped_ptr<ConditionVariable>(new ConditionVariable(&lock_)); | |
| 129 } | |
| 130 | |
| 131 } // namespace internal | |
| 132 } // base | |
| OLD | NEW |