OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/task_scheduler/scheduler_worker.h" | 5 #include "base/task_scheduler/scheduler_worker.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 // added to it. Otherwise, it will be destroyed at the end of this scope. | 91 // added to it. Otherwise, it will be destroyed at the end of this scope. |
92 if (!sequence_became_empty) | 92 if (!sequence_became_empty) |
93 outer_->delegate_->ReEnqueueSequence(std::move(sequence)); | 93 outer_->delegate_->ReEnqueueSequence(std::move(sequence)); |
94 | 94 |
95 // Calling WakeUp() guarantees that this SchedulerWorker will run | 95 // Calling WakeUp() guarantees that this SchedulerWorker will run |
96 // Tasks from Sequences returned by the GetWork() method of |delegate_| | 96 // Tasks from Sequences returned by the GetWork() method of |delegate_| |
97 // until it returns nullptr. Resetting |wake_up_event_| here doesn't break | 97 // until it returns nullptr. Resetting |wake_up_event_| here doesn't break |
98 // this invariant and avoids a useless loop iteration before going to | 98 // this invariant and avoids a useless loop iteration before going to |
99 // sleep if WakeUp() is called while this SchedulerWorker is awake. | 99 // sleep if WakeUp() is called while this SchedulerWorker is awake. |
100 wake_up_event_.Reset(); | 100 wake_up_event_.Reset(); |
101 } | 101 } |
fdoray
2017/02/08 17:59:01
There is a leak if someone does this:
TEST(...) {
robliao
2017/02/11 02:13:34
Thanks for pointing this out. This is covered by a
| |
102 | 102 |
103 // If a wake up is pending and we successfully detached, somehow |outer_| | 103 // If a wake up is pending and we successfully detached, somehow |outer_| |
104 // was able to signal us which means it probably thinks we're still alive. | 104 // was able to signal us which means it probably thinks we're still alive. |
105 // This is bad as it will cause the WakeUp to no-op and |outer_| will be | 105 // This is bad as it will cause the WakeUp to no-op and |outer_| will be |
106 // stuck forever. | 106 // stuck forever. |
107 DCHECK(!detached_thread || !IsWakeUpPending()) << | 107 DCHECK(!detached_thread || !IsWakeUpPending()) << |
108 "This thread was detached and woken up at the same time."; | 108 "This thread was detached and woken up at the same time."; |
109 } | 109 } |
110 | 110 |
111 void TakeOwnershipOfSchedulerWorker(std::unique_ptr<SchedulerWorker> worker) { | |
112 // If this check fails, we'll crash on a random thread instead. | |
113 CHECK(outer_ == worker.get()); | |
fdoray
2017/02/08 17:59:01
DCHECK_EQ
robliao
2017/02/10 00:04:04
This CHECK is intentional. I'd prefer to crash rig
| |
114 owning_worker_ = std::move(worker); | |
fdoray
2017/02/08 17:59:01
WakeUp();
Otherwise, the thread may sleep forever
robliao
2017/02/11 02:13:34
Done.
| |
115 } | |
116 | |
111 void Join() { PlatformThread::Join(thread_handle_); } | 117 void Join() { PlatformThread::Join(thread_handle_); } |
112 | 118 |
113 void WakeUp() { wake_up_event_.Signal(); } | 119 void WakeUp() { wake_up_event_.Signal(); } |
114 | 120 |
115 bool IsWakeUpPending() { return wake_up_event_.IsSignaled(); } | 121 bool IsWakeUpPending() { return wake_up_event_.IsSignaled(); } |
116 | 122 |
117 private: | 123 private: |
118 Thread(SchedulerWorker* outer) | 124 Thread(SchedulerWorker* outer) |
119 : outer_(outer), | 125 : outer_(outer), |
120 wake_up_event_(WaitableEvent::ResetPolicy::MANUAL, | 126 wake_up_event_(WaitableEvent::ResetPolicy::MANUAL, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 | 183 |
178 SchedulerWorker* outer_; | 184 SchedulerWorker* outer_; |
179 | 185 |
180 // Event signaled to wake up this thread. | 186 // Event signaled to wake up this thread. |
181 WaitableEvent wake_up_event_; | 187 WaitableEvent wake_up_event_; |
182 | 188 |
183 // Current priority of this thread. May be different from | 189 // Current priority of this thread. May be different from |
184 // |outer_->priority_hint_|. | 190 // |outer_->priority_hint_|. |
185 ThreadPriority current_thread_priority_; | 191 ThreadPriority current_thread_priority_; |
186 | 192 |
193 // Holds the owning worker for destruction at the end of detachment. | |
194 std::unique_ptr<SchedulerWorker> owning_worker_; | |
195 | |
187 DISALLOW_COPY_AND_ASSIGN(Thread); | 196 DISALLOW_COPY_AND_ASSIGN(Thread); |
188 }; | 197 }; |
189 | 198 |
190 std::unique_ptr<SchedulerWorker> SchedulerWorker::Create( | 199 std::unique_ptr<SchedulerWorker> SchedulerWorker::Create( |
191 ThreadPriority priority_hint, | 200 ThreadPriority priority_hint, |
192 std::unique_ptr<Delegate> delegate, | 201 std::unique_ptr<Delegate> delegate, |
193 TaskTracker* task_tracker, | 202 TaskTracker* task_tracker, |
194 InitialState initial_state, | 203 InitialState initial_state, |
195 SchedulerBackwardCompatibility backward_compatibility) { | 204 SchedulerBackwardCompatibility backward_compatibility) { |
196 auto worker = | 205 auto worker = |
(...skipping 11 matching lines...) Expand all Loading... | |
208 return worker; | 217 return worker; |
209 } | 218 } |
210 | 219 |
211 SchedulerWorker::~SchedulerWorker() { | 220 SchedulerWorker::~SchedulerWorker() { |
212 // It is unexpected for |thread_| to be alive and for SchedulerWorker to | 221 // It is unexpected for |thread_| to be alive and for SchedulerWorker to |
213 // destroy since SchedulerWorker owns the delegate needed by |thread_|. | 222 // destroy since SchedulerWorker owns the delegate needed by |thread_|. |
214 // For testing, this generally means JoinForTesting was not called. | 223 // For testing, this generally means JoinForTesting was not called. |
215 DCHECK(!thread_); | 224 DCHECK(!thread_); |
216 } | 225 } |
217 | 226 |
227 // static | |
228 void SchedulerWorker::DestroyAfterDetachment( | |
229 std::unique_ptr<SchedulerWorker> worker) { | |
230 DCHECK(worker); | |
231 AutoSchedulerLock auto_lock(worker->thread_lock_); | |
232 if (worker->thread_) { | |
233 SchedulerWorker* raw_worker_pointer = worker.get(); | |
234 raw_worker_pointer->thread_->TakeOwnershipOfSchedulerWorker( | |
235 std::move(worker)); | |
236 } | |
237 } | |
238 | |
218 void SchedulerWorker::WakeUp() { | 239 void SchedulerWorker::WakeUp() { |
219 AutoSchedulerLock auto_lock(thread_lock_); | 240 AutoSchedulerLock auto_lock(thread_lock_); |
220 | 241 |
221 DCHECK(!should_exit_for_testing_.IsSet()); | 242 DCHECK(!should_exit_for_testing_.IsSet()); |
222 | 243 |
223 if (!thread_) | 244 if (!thread_) |
224 CreateThreadAssertSynchronized(); | 245 CreateThreadAssertSynchronized(); |
225 | 246 |
226 if (thread_) | 247 if (thread_) |
227 thread_->WakeUp(); | 248 thread_->WakeUp(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 thread_ = Thread::Create(this); | 317 thread_ = Thread::Create(this); |
297 } | 318 } |
298 | 319 |
299 void SchedulerWorker::CreateThreadAssertSynchronized() { | 320 void SchedulerWorker::CreateThreadAssertSynchronized() { |
300 thread_lock_.AssertAcquired(); | 321 thread_lock_.AssertAcquired(); |
301 CreateThread(); | 322 CreateThread(); |
302 } | 323 } |
303 | 324 |
304 } // namespace internal | 325 } // namespace internal |
305 } // namespace base | 326 } // namespace base |
OLD | NEW |