Chromium Code Reviews| 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 |