| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/message_loop/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 MessageLoop::~MessageLoop() { | 90 MessageLoop::~MessageLoop() { |
| 91 // If |pump_| is non-null, this message loop has been bound and should be the | 91 // If |pump_| is non-null, this message loop has been bound and should be the |
| 92 // current one on this thread. Otherwise, this loop is being destructed before | 92 // current one on this thread. Otherwise, this loop is being destructed before |
| 93 // it was bound to a thread, so a different message loop (or no loop at all) | 93 // it was bound to a thread, so a different message loop (or no loop at all) |
| 94 // may be current. | 94 // may be current. |
| 95 DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); | 95 DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); |
| 96 | 96 |
| 97 // iOS just attaches to the loop, it doesn't Run it. | 97 // iOS just attaches to the loop, it doesn't Run it. |
| 98 // TODO(stuartmorgan): Consider wiring up a Detach(). | 98 // TODO(stuartmorgan): Consider wiring up a Detach(). |
| 99 #if !defined(OS_IOS) | 99 #if !defined(OS_IOS) |
| 100 DCHECK(!run_loop_); | 100 // There should be no active RunLoops on this thread, unless this MessageLoop |
| 101 // isn't bound to the current thread (see other condition at the top of this |
| 102 // method). |
| 103 DCHECK((!pump_ && current() != this) || !GetTopMostRunLoop()); |
| 101 #endif | 104 #endif |
| 102 | 105 |
| 103 #if defined(OS_WIN) | 106 #if defined(OS_WIN) |
| 104 if (in_high_res_mode_) | 107 if (in_high_res_mode_) |
| 105 Time::ActivateHighResolutionTimer(false); | 108 Time::ActivateHighResolutionTimer(false); |
| 106 #endif | 109 #endif |
| 107 // Clean up any unprocessed tasks, but take care: deleting a task could | 110 // Clean up any unprocessed tasks, but take care: deleting a task could |
| 108 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 111 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
| 109 // limit on the number of times we will allow a deleted task to generate more | 112 // limit on the number of times we will allow a deleted task to generate more |
| 110 // tasks. Normally, we should only pass through this loop once or twice. If | 113 // tasks. Normally, we should only pass through this loop once or twice. If |
| (...skipping 18 matching lines...) Expand all Loading... |
| 129 | 132 |
| 130 // Tell the incoming queue that we are dying. | 133 // Tell the incoming queue that we are dying. |
| 131 incoming_task_queue_->WillDestroyCurrentMessageLoop(); | 134 incoming_task_queue_->WillDestroyCurrentMessageLoop(); |
| 132 incoming_task_queue_ = NULL; | 135 incoming_task_queue_ = NULL; |
| 133 unbound_task_runner_ = NULL; | 136 unbound_task_runner_ = NULL; |
| 134 task_runner_ = NULL; | 137 task_runner_ = NULL; |
| 135 | 138 |
| 136 // OK, now make it so that no one can find us. | 139 // OK, now make it so that no one can find us. |
| 137 if (current() == this) | 140 if (current() == this) |
| 138 GetTLSMessageLoop()->Set(nullptr); | 141 GetTLSMessageLoop()->Set(nullptr); |
| 139 | |
| 140 RunLoop::ResetTLSState(); | |
| 141 } | 142 } |
| 142 | 143 |
| 143 // static | 144 // static |
| 144 MessageLoop* MessageLoop::current() { | 145 MessageLoop* MessageLoop::current() { |
| 145 // TODO(darin): sadly, we cannot enable this yet since people call us even | 146 // TODO(darin): sadly, we cannot enable this yet since people call us even |
| 146 // when they have no intention of using us. | 147 // when they have no intention of using us. |
| 147 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 148 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
| 148 return GetTLSMessageLoop()->Get(); | 149 return GetTLSMessageLoop()->Get(); |
| 149 } | 150 } |
| 150 | 151 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 } | 210 } |
| 210 | 211 |
| 211 void MessageLoop::RemoveDestructionObserver( | 212 void MessageLoop::RemoveDestructionObserver( |
| 212 DestructionObserver* destruction_observer) { | 213 DestructionObserver* destruction_observer) { |
| 213 DCHECK_EQ(this, current()); | 214 DCHECK_EQ(this, current()); |
| 214 destruction_observers_.RemoveObserver(destruction_observer); | 215 destruction_observers_.RemoveObserver(destruction_observer); |
| 215 } | 216 } |
| 216 | 217 |
| 217 void MessageLoop::QuitWhenIdle() { | 218 void MessageLoop::QuitWhenIdle() { |
| 218 DCHECK_EQ(this, current()); | 219 DCHECK_EQ(this, current()); |
| 219 if (run_loop_) { | 220 DCHECK(GetTopMostRunLoop()) << "Must be inside Run to call QuitWhenIdle"; |
| 220 run_loop_->QuitWhenIdle(); | 221 GetTopMostRunLoop()->QuitWhenIdle(); |
| 221 } else { | |
| 222 NOTREACHED() << "Must be inside Run to call QuitWhenIdle"; | |
| 223 } | |
| 224 } | 222 } |
| 225 | 223 |
| 226 void MessageLoop::QuitNow() { | 224 void MessageLoop::QuitNow() { |
| 227 DCHECK_EQ(this, current()); | 225 DCHECK_EQ(this, current()); |
| 228 if (run_loop_) { | 226 DCHECK(GetTopMostRunLoop()) << "Must be inside Run to call Quit"; |
| 229 pump_->Quit(); | 227 pump_->Quit(); |
| 230 } else { | |
| 231 NOTREACHED() << "Must be inside Run to call Quit"; | |
| 232 } | |
| 233 } | 228 } |
| 234 | 229 |
| 235 bool MessageLoop::IsType(Type type) const { | 230 bool MessageLoop::IsType(Type type) const { |
| 236 return type_ == type; | 231 return type_ == type; |
| 237 } | 232 } |
| 238 | 233 |
| 239 static void QuitCurrentWhenIdle() { | 234 static void QuitCurrentWhenIdle() { |
| 240 MessageLoop::current()->QuitWhenIdle(); | 235 MessageLoop::current()->QuitWhenIdle(); |
| 241 } | 236 } |
| 242 | 237 |
| 243 // static | 238 // static |
| 244 Closure MessageLoop::QuitWhenIdleClosure() { | 239 Closure MessageLoop::QuitWhenIdleClosure() { |
| 245 return Bind(&QuitCurrentWhenIdle); | 240 return Bind(&QuitCurrentWhenIdle); |
| 246 } | 241 } |
| 247 | 242 |
| 248 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 243 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
| 249 if (allowed) { | 244 if (allowed) { |
| 250 CHECK(base::RunLoop::IsNestingAllowedOnCurrentThread()); | 245 CHECK(RunLoop::IsNestingAllowedOnCurrentThread()); |
| 251 | 246 |
| 252 // Kick the native pump just in case we enter a OS-driven nested message | 247 // Kick the native pump just in case we enter a OS-driven nested message |
| 253 // loop. | 248 // loop. |
| 254 pump_->ScheduleWork(); | 249 pump_->ScheduleWork(); |
| 255 } | 250 } |
| 256 nestable_tasks_allowed_ = allowed; | 251 nestable_tasks_allowed_ = allowed; |
| 257 } | 252 } |
| 258 | 253 |
| 259 bool MessageLoop::NestableTasksAllowed() const { | 254 bool MessageLoop::NestableTasksAllowed() const { |
| 260 return nestable_tasks_allowed_; | 255 return nestable_tasks_allowed_; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 } | 290 } |
| 296 | 291 |
| 297 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) | 292 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) |
| 298 : type_(type), | 293 : type_(type), |
| 299 #if defined(OS_WIN) | 294 #if defined(OS_WIN) |
| 300 pending_high_res_tasks_(0), | 295 pending_high_res_tasks_(0), |
| 301 in_high_res_mode_(false), | 296 in_high_res_mode_(false), |
| 302 #endif | 297 #endif |
| 303 nestable_tasks_allowed_(true), | 298 nestable_tasks_allowed_(true), |
| 304 pump_factory_(std::move(pump_factory)), | 299 pump_factory_(std::move(pump_factory)), |
| 305 run_loop_(nullptr), | |
| 306 current_pending_task_(nullptr), | 300 current_pending_task_(nullptr), |
| 307 incoming_task_queue_(new internal::IncomingTaskQueue(this)), | 301 incoming_task_queue_(new internal::IncomingTaskQueue(this)), |
| 308 unbound_task_runner_( | 302 unbound_task_runner_( |
| 309 new internal::MessageLoopTaskRunner(incoming_task_queue_)), | 303 new internal::MessageLoopTaskRunner(incoming_task_queue_)), |
| 310 task_runner_(unbound_task_runner_), | 304 task_runner_(unbound_task_runner_), |
| 311 thread_id_(kInvalidThreadId) { | 305 thread_id_(kInvalidThreadId) { |
| 312 // If type is TYPE_CUSTOM non-null pump_factory must be given. | 306 // If type is TYPE_CUSTOM non-null pump_factory must be given. |
| 313 DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null()); | 307 DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null()); |
| 314 } | 308 } |
| 315 | 309 |
| 316 void MessageLoop::BindToCurrentThread() { | |
| 317 DCHECK(!pump_); | |
| 318 if (!pump_factory_.is_null()) | |
| 319 pump_ = std::move(pump_factory_).Run(); | |
| 320 else | |
| 321 pump_ = CreateMessagePumpForType(type_); | |
| 322 | |
| 323 DCHECK(!current()) << "should only have one message loop per thread"; | |
| 324 GetTLSMessageLoop()->Set(this); | |
| 325 | |
| 326 incoming_task_queue_->StartScheduling(); | |
| 327 unbound_task_runner_->BindToCurrentThread(); | |
| 328 unbound_task_runner_ = nullptr; | |
| 329 SetThreadTaskRunnerHandle(); | |
| 330 thread_id_ = PlatformThread::CurrentId(); | |
| 331 } | |
| 332 | |
| 333 std::string MessageLoop::GetThreadName() const { | 310 std::string MessageLoop::GetThreadName() const { |
| 334 DCHECK_NE(kInvalidThreadId, thread_id_) | 311 DCHECK_NE(kInvalidThreadId, thread_id_) |
| 335 << "GetThreadName() must only be called after BindToCurrentThread()'s " | 312 << "GetThreadName() must only be called after BindToCurrentThread()'s " |
| 336 << "side-effects have been synchronized with this thread."; | 313 << "side-effects have been synchronized with this thread."; |
| 337 return ThreadIdNameManager::GetInstance()->GetName(thread_id_); | 314 return ThreadIdNameManager::GetInstance()->GetName(thread_id_); |
| 338 } | 315 } |
| 339 | 316 |
| 340 void MessageLoop::SetTaskRunner( | 317 void MessageLoop::SetTaskRunner( |
| 341 scoped_refptr<SingleThreadTaskRunner> task_runner) { | 318 scoped_refptr<SingleThreadTaskRunner> task_runner) { |
| 342 DCHECK_EQ(this, current()); | 319 DCHECK_EQ(this, current()); |
| 343 DCHECK(task_runner); | 320 DCHECK(task_runner); |
| 344 DCHECK(task_runner->BelongsToCurrentThread()); | 321 DCHECK(task_runner->BelongsToCurrentThread()); |
| 345 DCHECK(!unbound_task_runner_); | 322 DCHECK(!unbound_task_runner_); |
| 346 task_runner_ = std::move(task_runner); | 323 task_runner_ = std::move(task_runner); |
| 347 SetThreadTaskRunnerHandle(); | 324 SetThreadTaskRunnerHandle(); |
| 348 } | 325 } |
| 349 | 326 |
| 350 void MessageLoop::ClearTaskRunnerForTesting() { | 327 void MessageLoop::ClearTaskRunnerForTesting() { |
| 351 DCHECK_EQ(this, current()); | 328 DCHECK_EQ(this, current()); |
| 352 DCHECK(!unbound_task_runner_); | 329 DCHECK(!unbound_task_runner_); |
| 353 task_runner_ = nullptr; | 330 task_runner_ = nullptr; |
| 354 thread_task_runner_handle_.reset(); | 331 thread_task_runner_handle_.reset(); |
| 355 } | 332 } |
| 356 | 333 |
| 334 void MessageLoop::BindToCurrentThread() { |
| 335 RunLoop::Delegate::BindToCurrentThread(); |
| 336 |
| 337 DCHECK(!pump_); |
| 338 if (!pump_factory_.is_null()) |
| 339 pump_ = std::move(pump_factory_).Run(); |
| 340 else |
| 341 pump_ = CreateMessagePumpForType(type_); |
| 342 |
| 343 DCHECK(!current()) << "should only have one message loop per thread"; |
| 344 GetTLSMessageLoop()->Set(this); |
| 345 |
| 346 incoming_task_queue_->StartScheduling(); |
| 347 unbound_task_runner_->BindToCurrentThread(); |
| 348 unbound_task_runner_ = nullptr; |
| 349 SetThreadTaskRunnerHandle(); |
| 350 thread_id_ = PlatformThread::CurrentId(); |
| 351 } |
| 352 |
| 353 void MessageLoop::Run() { |
| 354 DCHECK_EQ(this, current()); |
| 355 pump_->Run(this); |
| 356 } |
| 357 |
| 358 void MessageLoop::Quit() { |
| 359 DCHECK_EQ(this, current()); |
| 360 QuitNow(); |
| 361 } |
| 362 |
| 357 void MessageLoop::SetThreadTaskRunnerHandle() { | 363 void MessageLoop::SetThreadTaskRunnerHandle() { |
| 358 DCHECK_EQ(this, current()); | 364 DCHECK_EQ(this, current()); |
| 359 // Clear the previous thread task runner first, because only one can exist at | 365 // Clear the previous thread task runner first, because only one can exist at |
| 360 // a time. | 366 // a time. |
| 361 thread_task_runner_handle_.reset(); | 367 thread_task_runner_handle_.reset(); |
| 362 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_)); | 368 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_)); |
| 363 } | 369 } |
| 364 | 370 |
| 365 void MessageLoop::RunHandler() { | |
| 366 DCHECK_EQ(this, current()); | |
| 367 DCHECK(run_loop_); | |
| 368 pump_->Run(this); | |
| 369 } | |
| 370 | |
| 371 bool MessageLoop::ProcessNextDelayedNonNestableTask() { | 371 bool MessageLoop::ProcessNextDelayedNonNestableTask() { |
| 372 if (is_nested_) | 372 if (IsNested()) |
| 373 return false; | 373 return false; |
| 374 | 374 |
| 375 if (deferred_non_nestable_work_queue_.empty()) | 375 if (deferred_non_nestable_work_queue_.empty()) |
| 376 return false; | 376 return false; |
| 377 | 377 |
| 378 PendingTask pending_task = | 378 PendingTask pending_task = |
| 379 std::move(deferred_non_nestable_work_queue_.front()); | 379 std::move(deferred_non_nestable_work_queue_.front()); |
| 380 deferred_non_nestable_work_queue_.pop(); | 380 deferred_non_nestable_work_queue_.pop(); |
| 381 | 381 |
| 382 RunTask(&pending_task); | 382 RunTask(&pending_task); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 404 task_annotator_.RunTask("MessageLoop::PostTask", pending_task); | 404 task_annotator_.RunTask("MessageLoop::PostTask", pending_task); |
| 405 for (auto& observer : task_observers_) | 405 for (auto& observer : task_observers_) |
| 406 observer.DidProcessTask(*pending_task); | 406 observer.DidProcessTask(*pending_task); |
| 407 | 407 |
| 408 nestable_tasks_allowed_ = true; | 408 nestable_tasks_allowed_ = true; |
| 409 | 409 |
| 410 current_pending_task_ = nullptr; | 410 current_pending_task_ = nullptr; |
| 411 } | 411 } |
| 412 | 412 |
| 413 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) { | 413 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) { |
| 414 if (pending_task.nestable || !is_nested_) { | 414 if (pending_task.nestable || !IsNested()) { |
| 415 RunTask(&pending_task); | 415 RunTask(&pending_task); |
| 416 // Show that we ran a task (Note: a new one might arrive as a | 416 // Show that we ran a task (Note: a new one might arrive as a |
| 417 // consequence!). | 417 // consequence!). |
| 418 return true; | 418 return true; |
| 419 } | 419 } |
| 420 | 420 |
| 421 // We couldn't run the task now because we're in a nested run loop | 421 // We couldn't run the task now because we're in a nested run loop |
| 422 // and the task isn't nestable. | 422 // and the task isn't nestable. |
| 423 deferred_non_nestable_work_queue_.push(std::move(pending_task)); | 423 deferred_non_nestable_work_queue_.push(std::move(pending_task)); |
| 424 return false; | 424 return false; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 if (!delayed_work_queue_.empty()) | 539 if (!delayed_work_queue_.empty()) |
| 540 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; | 540 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; |
| 541 | 541 |
| 542 return DeferOrRunPendingTask(std::move(pending_task)); | 542 return DeferOrRunPendingTask(std::move(pending_task)); |
| 543 } | 543 } |
| 544 | 544 |
| 545 bool MessageLoop::DoIdleWork() { | 545 bool MessageLoop::DoIdleWork() { |
| 546 if (ProcessNextDelayedNonNestableTask()) | 546 if (ProcessNextDelayedNonNestableTask()) |
| 547 return true; | 547 return true; |
| 548 | 548 |
| 549 if (run_loop_->quit_when_idle_received_) | 549 if (GetTopMostRunLoop()->quit_when_idle_received_) |
| 550 pump_->Quit(); | 550 pump_->Quit(); |
| 551 | 551 |
| 552 // When we return we will do a kernel wait for more tasks. | 552 // When we return we will do a kernel wait for more tasks. |
| 553 #if defined(OS_WIN) | 553 #if defined(OS_WIN) |
| 554 // On Windows we activate the high resolution timer so that the wait | 554 // On Windows we activate the high resolution timer so that the wait |
| 555 // _if_ triggered by the timer happens with good resolution. If we don't | 555 // _if_ triggered by the timer happens with good resolution. If we don't |
| 556 // do this the default resolution is 15ms which might not be acceptable | 556 // do this the default resolution is 15ms which might not be acceptable |
| 557 // for some tasks. | 557 // for some tasks. |
| 558 bool high_res = pending_high_res_tasks_ > 0; | 558 bool high_res = pending_high_res_tasks_ > 0; |
| 559 if (high_res != in_high_res_mode_) { | 559 if (high_res != in_high_res_mode_) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 persistent, | 642 persistent, |
| 643 mode, | 643 mode, |
| 644 controller, | 644 controller, |
| 645 delegate); | 645 delegate); |
| 646 } | 646 } |
| 647 #endif | 647 #endif |
| 648 | 648 |
| 649 #endif // !defined(OS_NACL_SFI) | 649 #endif // !defined(OS_NACL_SFI) |
| 650 | 650 |
| 651 } // namespace base | 651 } // namespace base |
| OLD | NEW |