Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: base/task_scheduler/scheduler_lock_impl.cc

Issue 1706123002: TaskScheduler [2/9] Scheduler Lock (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Thread Local Acquired Lock Vector and CR Feedback Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/synchronization/condition_variable.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/threading/thread_local.h"
16
17 namespace base {
18 namespace internal {
19
20 namespace {
21
22 class SafeAcquisitionTracker {
23 public:
24 SafeAcquisitionTracker() = default;
25
26 void RegisterLock(
27 const SchedulerLockImpl* const lock,
28 const SchedulerLockImpl* const predecessor) {
29 // Reentrant locks are unsupported.
30 DCHECK(lock != predecessor);
31 AutoLock auto_lock(metadata_lock_);
32 allowed_predecessor_map_[lock] = predecessor;
33 AssertSafePredecessor(lock);
34 }
35
36 void UnregisterLock(const SchedulerLockImpl* const lock) {
37 AutoLock auto_lock(metadata_lock_);
38 allowed_predecessor_map_.erase(lock);
39 }
40
41 void RecordAcquisition(const SchedulerLockImpl* const lock) {
42 AutoLock auto_lock(metadata_lock_);
gab 2016/02/22 16:54:12 Move AutoLock into AssertSafeAcquire (on the line
robliao 2016/02/22 18:38:09 Done.
43 const PlatformThreadId id = PlatformThread::CurrentId();
44 AssertSafeAcquire(id, lock);
45 if (!tls_acquired_locks_.Get())
46 tls_acquired_locks_.Set(new LockVector);
47
48 tls_acquired_locks_.Get()->push_back(lock);
49 }
50
51 void RecordRelease(const SchedulerLockImpl* const lock) {
52 AutoLock auto_lock(metadata_lock_);
gab 2016/02/22 16:54:12 No need to lock, right?
robliao 2016/02/22 18:38:09 Indeed. It's all TLS only. Removed.
53 LockVector* acquired_locks = tls_acquired_locks_.Get();
gab 2016/02/22 16:54:12 DCHECK(acquired_locks);
robliao 2016/02/22 18:38:09 DCHECK isn't necessary here as we'll simply crash
gab 2016/02/22 19:56:47 Right but DCHECK explicitly documents expectations
robliao 2016/02/22 20:22:51 I used to be on the DCHECK pointers side as well u
gab 2016/02/22 20:36:31 To me it acts as explicit documentation whereas im
robliao 2016/02/22 21:21:02 Discussed offline and rendered moot with the allow
54 const auto iter_at_lock =
55 std::find(acquired_locks->begin(), acquired_locks->end(), lock);
56 DCHECK(iter_at_lock != acquired_locks->end());
57 acquired_locks->erase(iter_at_lock);
58 if (acquired_locks->empty()) {
59 tls_acquired_locks_.Set(nullptr);
60 delete acquired_locks;
gab 2016/02/22 16:54:12 Assuming this thread remains active, it will soon
robliao 2016/02/22 18:38:09 The destruction of a lock does not necessarily cor
gab 2016/02/22 19:56:47 Duh of course, I did mean on destruction of thread
robliao 2016/02/22 20:22:51 The right way to do this is to introduce the destr
robliao 2016/02/22 20:37:34 Looks like I incorrectly assumed that this API was
61 }
62 }
63
64 private:
65 using LockVector = std::vector<const SchedulerLockImpl*>;
66 using PredecessorMap = std::unordered_map<
67 const SchedulerLockImpl*, const SchedulerLockImpl*>;
68 using AcquisitionMap =
gab 2016/02/22 16:54:12 rm unused type
robliao 2016/02/22 18:38:09 Done.
69 std::unordered_map<base::PlatformThreadId, LockVector>;
fdoray 2016/02/22 16:45:21 not used anymore
robliao 2016/02/22 18:38:09 Done.
70
71 // This asserts that the lock is safe to acquire. This means that this should
72 // be run before actually recording the acquisition.
73 void AssertSafeAcquire(PlatformThreadId id,
74 const SchedulerLockImpl* const lock) const {
75 const LockVector* acquired_locks = GetThreadAcquiredLocks();
76
77 // If the thread currently holds no locks, this is inherently safe.
78 if (!acquired_locks)
79 return;
80
81 // We're getting ready to look at the allowed_predecessor_map_.
gab 2016/02/22 16:54:12 When the line below is changed to an AutoLock as s
robliao 2016/02/22 18:38:09 Done.
82 metadata_lock_.AssertAcquired();
83
84 // Otherwise, make sure that the previous lock acquired is an allowed
85 // predecessor.
86 const SchedulerLockImpl* allowed_predecessor =
87 allowed_predecessor_map_.at(lock);
88 DCHECK(acquired_locks->back() == allowed_predecessor);
89 }
90
91 void AssertSafePredecessor(const SchedulerLockImpl* lock) const {
92 metadata_lock_.AssertAcquired();
93 for (const SchedulerLockImpl* predecessor =
94 allowed_predecessor_map_.at(lock);
95 predecessor != nullptr;
96 predecessor = allowed_predecessor_map_.at(predecessor)) {
97 if (predecessor == lock)
98 NOTREACHED();
99 }
100 }
101
102 const LockVector* GetThreadAcquiredLocks() const {
103 // ThreadLocalPointer.Get() has no const version.
104 return const_cast<SafeAcquisitionTracker*>(this)->tls_acquired_locks_.Get();
gab 2016/02/22 16:54:12 I'd prefer to inline this at single call site, oth
robliao 2016/02/22 18:38:09 Done.
105 }
106
107 // Synchronizes everything in SafeAcquisitionTracker.
108 Lock metadata_lock_;
gab 2016/02/22 16:54:12 // Synchronized access to |allowed_predecessor_map
robliao 2016/02/22 18:38:09 Done.
109
110 PredecessorMap allowed_predecessor_map_;
111 ThreadLocalPointer<LockVector> tls_acquired_locks_;
112
113 DISALLOW_COPY_AND_ASSIGN(SafeAcquisitionTracker);
114 };
115
116 LazyInstance<SafeAcquisitionTracker>::Leaky g_safe_acquisition_tracker =
117 LAZY_INSTANCE_INITIALIZER;
118
119 } // namespace
120
121 SchedulerLockImpl::SchedulerLockImpl() : SchedulerLockImpl(nullptr) {}
122
123 SchedulerLockImpl::SchedulerLockImpl(const SchedulerLockImpl* predecessor) {
124 g_safe_acquisition_tracker.Get().RegisterLock(this, predecessor);
125 }
126
127 SchedulerLockImpl::~SchedulerLockImpl() {
128 g_safe_acquisition_tracker.Get().UnregisterLock(this);
129 }
130
131 void SchedulerLockImpl::Acquire() {
132 lock_.Acquire();
133 g_safe_acquisition_tracker.Get().RecordAcquisition(this);
134 }
135
136 void SchedulerLockImpl::Release() {
137 lock_.Release();
138 g_safe_acquisition_tracker.Get().RecordRelease(this);
139 }
140
141 void SchedulerLockImpl::AssertAcquired() const {
142 lock_.AssertAcquired();
143 }
144
145 scoped_ptr<ConditionVariable> SchedulerLockImpl::CreateConditionVariable() {
146 return scoped_ptr<ConditionVariable>(new ConditionVariable(&lock_));
147 }
148
149 } // namespace internal
150 } // base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698