| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 WaitForWork(); | 42 WaitForWork(); |
| 43 | 43 |
| 44 while (!outer_->task_tracker_->IsShutdownComplete() && | 44 while (!outer_->task_tracker_->IsShutdownComplete() && |
| 45 !outer_->ShouldExitForTesting()) { | 45 !outer_->ShouldExitForTesting()) { |
| 46 DCHECK(outer_); | 46 DCHECK(outer_); |
| 47 | 47 |
| 48 #if defined(OS_MACOSX) | 48 #if defined(OS_MACOSX) |
| 49 mac::ScopedNSAutoreleasePool autorelease_pool; | 49 mac::ScopedNSAutoreleasePool autorelease_pool; |
| 50 #endif | 50 #endif |
| 51 | 51 |
| 52 #if !defined(OS_LINUX) | |
| 53 UpdateThreadPriority(GetDesiredThreadPriority()); | 52 UpdateThreadPriority(GetDesiredThreadPriority()); |
| 54 #endif | |
| 55 | 53 |
| 56 // Get the sequence containing the next task to execute. | 54 // Get the sequence containing the next task to execute. |
| 57 scoped_refptr<Sequence> sequence = outer_->delegate_->GetWork(outer_); | 55 scoped_refptr<Sequence> sequence = outer_->delegate_->GetWork(outer_); |
| 58 if (!sequence) { | 56 if (!sequence) { |
| 59 if (outer_->delegate_->CanDetach(outer_)) { | 57 if (outer_->delegate_->CanDetach(outer_)) { |
| 60 detached_thread = outer_->Detach(); | 58 detached_thread = outer_->Detach(); |
| 61 if (detached_thread) { | 59 if (detached_thread) { |
| 62 DCHECK_EQ(detached_thread.get(), this); | 60 DCHECK_EQ(detached_thread.get(), this); |
| 63 PlatformThread::Detach(thread_handle_); | 61 PlatformThread::Detach(thread_handle_); |
| 64 outer_ = nullptr; | 62 outer_ = nullptr; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 if (sleep_time.is_max()) { | 122 if (sleep_time.is_max()) { |
| 125 // Calling TimedWait with TimeDelta::Max is not recommended per | 123 // Calling TimedWait with TimeDelta::Max is not recommended per |
| 126 // http://crbug.com/465948. | 124 // http://crbug.com/465948. |
| 127 wake_up_event_.Wait(); | 125 wake_up_event_.Wait(); |
| 128 } else { | 126 } else { |
| 129 wake_up_event_.TimedWait(sleep_time); | 127 wake_up_event_.TimedWait(sleep_time); |
| 130 } | 128 } |
| 131 wake_up_event_.Reset(); | 129 wake_up_event_.Reset(); |
| 132 } | 130 } |
| 133 | 131 |
| 134 // Returns the desired thread priority based on the worker priority and the | 132 // Returns the priority for which the thread should be set based on the |
| 135 // current shutdown state. | 133 // priority hint, current shutdown state, and platform capabilities. |
| 136 ThreadPriority GetDesiredThreadPriority() { | 134 ThreadPriority GetDesiredThreadPriority() { |
| 137 DCHECK(outer_); | 135 DCHECK(outer_); |
| 138 | 136 |
| 139 if (outer_->task_tracker_->HasShutdownStarted() && | 137 // All threads have a NORMAL priority when Lock doesn't handle multiple |
| 140 static_cast<int>(outer_->thread_priority_) < | 138 // thread priorities. |
| 141 static_cast<int>(ThreadPriority::NORMAL)) { | 139 if (!Lock::HandlesMultipleThreadPriorities()) |
| 140 return ThreadPriority::NORMAL; |
| 141 |
| 142 // To avoid shutdown hangs, disallow a priority below NORMAL during |
| 143 // shutdown. If thread priority cannot be increased, never allow a priority |
| 144 // below NORMAL. |
| 145 if (static_cast<int>(outer_->priority_hint_) < |
| 146 static_cast<int>(ThreadPriority::NORMAL) && |
| 147 (outer_->task_tracker_->HasShutdownStarted() || |
| 148 !PlatformThread::CanIncreaseCurrentThreadPriority())) { |
| 142 return ThreadPriority::NORMAL; | 149 return ThreadPriority::NORMAL; |
| 143 } | 150 } |
| 144 return outer_->thread_priority_; | 151 |
| 152 return outer_->priority_hint_; |
| 145 } | 153 } |
| 146 | 154 |
| 147 // Increasing the thread priority requires the CAP_SYS_NICE capability on | |
| 148 // Linux. | |
| 149 #if !defined(OS_LINUX) | |
| 150 void UpdateThreadPriority(ThreadPriority desired_thread_priority) { | 155 void UpdateThreadPriority(ThreadPriority desired_thread_priority) { |
| 151 if (desired_thread_priority == current_thread_priority_) | 156 if (desired_thread_priority == current_thread_priority_) |
| 152 return; | 157 return; |
| 153 | 158 |
| 154 PlatformThread::SetCurrentThreadPriority(desired_thread_priority); | 159 PlatformThread::SetCurrentThreadPriority(desired_thread_priority); |
| 155 current_thread_priority_ = desired_thread_priority; | 160 current_thread_priority_ = desired_thread_priority; |
| 156 } | 161 } |
| 157 #endif // !defined(OS_LINUX) | |
| 158 | 162 |
| 159 PlatformThreadHandle thread_handle_; | 163 PlatformThreadHandle thread_handle_; |
| 160 | 164 |
| 161 SchedulerWorker* outer_; | 165 SchedulerWorker* outer_; |
| 162 | 166 |
| 163 // Event signaled to wake up this thread. | 167 // Event signaled to wake up this thread. |
| 164 WaitableEvent wake_up_event_; | 168 WaitableEvent wake_up_event_; |
| 165 | 169 |
| 166 // Current priority of this thread. May be different from | 170 // Current priority of this thread. May be different from |
| 167 // |outer_->thread_priority_| during shutdown. | 171 // |outer_->priority_hint_|. |
| 168 ThreadPriority current_thread_priority_; | 172 ThreadPriority current_thread_priority_; |
| 169 | 173 |
| 170 DISALLOW_COPY_AND_ASSIGN(Thread); | 174 DISALLOW_COPY_AND_ASSIGN(Thread); |
| 171 }; | 175 }; |
| 172 | 176 |
| 173 std::unique_ptr<SchedulerWorker> SchedulerWorker::Create( | 177 std::unique_ptr<SchedulerWorker> SchedulerWorker::Create( |
| 174 ThreadPriority thread_priority, | 178 ThreadPriority priority_hint, |
| 175 std::unique_ptr<Delegate> delegate, | 179 std::unique_ptr<Delegate> delegate, |
| 176 TaskTracker* task_tracker, | 180 TaskTracker* task_tracker, |
| 177 InitialState initial_state) { | 181 InitialState initial_state) { |
| 178 std::unique_ptr<SchedulerWorker> worker( | 182 std::unique_ptr<SchedulerWorker> worker( |
| 179 new SchedulerWorker(thread_priority, std::move(delegate), task_tracker)); | 183 new SchedulerWorker(priority_hint, std::move(delegate), task_tracker)); |
| 180 // Creation happens before any other thread can reference this one, so no | 184 // Creation happens before any other thread can reference this one, so no |
| 181 // synchronization is necessary. | 185 // synchronization is necessary. |
| 182 if (initial_state == SchedulerWorker::InitialState::ALIVE) { | 186 if (initial_state == SchedulerWorker::InitialState::ALIVE) { |
| 183 worker->CreateThread(); | 187 worker->CreateThread(); |
| 184 if (!worker->thread_) { | 188 if (!worker->thread_) { |
| 185 return nullptr; | 189 return nullptr; |
| 186 } | 190 } |
| 187 } | 191 } |
| 188 | 192 |
| 189 return worker; | 193 return worker; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 thread_->Join(); | 225 thread_->Join(); |
| 222 | 226 |
| 223 thread_.reset(); | 227 thread_.reset(); |
| 224 } | 228 } |
| 225 | 229 |
| 226 bool SchedulerWorker::ThreadAliveForTesting() const { | 230 bool SchedulerWorker::ThreadAliveForTesting() const { |
| 227 AutoSchedulerLock auto_lock(thread_lock_); | 231 AutoSchedulerLock auto_lock(thread_lock_); |
| 228 return !!thread_; | 232 return !!thread_; |
| 229 } | 233 } |
| 230 | 234 |
| 231 SchedulerWorker::SchedulerWorker(ThreadPriority thread_priority, | 235 SchedulerWorker::SchedulerWorker(ThreadPriority priority_hint, |
| 232 std::unique_ptr<Delegate> delegate, | 236 std::unique_ptr<Delegate> delegate, |
| 233 TaskTracker* task_tracker) | 237 TaskTracker* task_tracker) |
| 234 : thread_priority_(thread_priority), | 238 : priority_hint_(priority_hint), |
| 235 delegate_(std::move(delegate)), | 239 delegate_(std::move(delegate)), |
| 236 task_tracker_(task_tracker) { | 240 task_tracker_(task_tracker) { |
| 237 DCHECK(delegate_); | 241 DCHECK(delegate_); |
| 238 DCHECK(task_tracker_); | 242 DCHECK(task_tracker_); |
| 239 } | 243 } |
| 240 | 244 |
| 241 std::unique_ptr<SchedulerWorker::Thread> SchedulerWorker::Detach() { | 245 std::unique_ptr<SchedulerWorker::Thread> SchedulerWorker::Detach() { |
| 242 DCHECK(!ShouldExitForTesting()) << "Worker was already joined"; | 246 DCHECK(!ShouldExitForTesting()) << "Worker was already joined"; |
| 243 AutoSchedulerLock auto_lock(thread_lock_); | 247 AutoSchedulerLock auto_lock(thread_lock_); |
| 244 // If a wakeup is pending, then a WakeUp() came in while we were deciding to | 248 // If a wakeup is pending, then a WakeUp() came in while we were deciding to |
| (...skipping 11 matching lines...) Expand all Loading... |
| 256 CreateThread(); | 260 CreateThread(); |
| 257 } | 261 } |
| 258 | 262 |
| 259 bool SchedulerWorker::ShouldExitForTesting() const { | 263 bool SchedulerWorker::ShouldExitForTesting() const { |
| 260 AutoSchedulerLock auto_lock(should_exit_for_testing_lock_); | 264 AutoSchedulerLock auto_lock(should_exit_for_testing_lock_); |
| 261 return should_exit_for_testing_; | 265 return should_exit_for_testing_; |
| 262 } | 266 } |
| 263 | 267 |
| 264 } // namespace internal | 268 } // namespace internal |
| 265 } // namespace base | 269 } // namespace base |
| OLD | NEW |