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

Side by Side Diff: base/message_loop.cc

Issue 10479018: Add base::RunLoop and update ui_test_utils to use it to reduce flakiness (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: darin feedback Created 8 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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.h" 5 #include "base/message_loop.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/debug/alias.h" 11 #include "base/debug/alias.h"
12 #include "base/debug/trace_event.h" 12 #include "base/debug/trace_event.h"
13 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop_proxy_impl.h" 16 #include "base/message_loop_proxy_impl.h"
17 #include "base/message_pump_default.h" 17 #include "base/message_pump_default.h"
18 #include "base/metrics/histogram.h" 18 #include "base/metrics/histogram.h"
19 #include "base/run_loop.h"
19 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
20 #include "base/thread_task_runner_handle.h" 21 #include "base/thread_task_runner_handle.h"
21 #include "base/threading/thread_local.h" 22 #include "base/threading/thread_local.h"
22 #include "base/time.h" 23 #include "base/time.h"
23 #include "base/tracked_objects.h" 24 #include "base/tracked_objects.h"
24 25
25 #if defined(OS_MACOSX) 26 #if defined(OS_MACOSX)
26 #include "base/message_pump_mac.h" 27 #include "base/message_pump_mac.h"
27 #endif 28 #endif
28 #if defined(OS_POSIX) 29 #if defined(OS_POSIX)
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 MessageLoop::DestructionObserver::~DestructionObserver() { 125 MessageLoop::DestructionObserver::~DestructionObserver() {
125 } 126 }
126 127
127 //------------------------------------------------------------------------------ 128 //------------------------------------------------------------------------------
128 129
129 MessageLoop::MessageLoop(Type type) 130 MessageLoop::MessageLoop(Type type)
130 : type_(type), 131 : type_(type),
131 nestable_tasks_allowed_(true), 132 nestable_tasks_allowed_(true),
132 exception_restoration_(false), 133 exception_restoration_(false),
133 message_histogram_(NULL), 134 message_histogram_(NULL),
134 state_(NULL),
135 #ifdef OS_WIN 135 #ifdef OS_WIN
136 os_modal_loop_(false), 136 os_modal_loop_(false),
137 #endif // OS_WIN 137 #endif // OS_WIN
138 next_sequence_num_(0) { 138 next_sequence_num_(0) {
139 DCHECK(!current()) << "should only have one message loop per thread"; 139 DCHECK(!current()) << "should only have one message loop per thread";
140 lazy_tls_ptr.Pointer()->Set(this); 140 lazy_tls_ptr.Pointer()->Set(this);
141 141
142 message_loop_proxy_ = new base::MessageLoopProxyImpl(); 142 message_loop_proxy_ = new base::MessageLoopProxyImpl();
143 thread_task_runner_handle_.reset( 143 thread_task_runner_handle_.reset(
144 new base::ThreadTaskRunnerHandle(message_loop_proxy_)); 144 new base::ThreadTaskRunnerHandle(message_loop_proxy_));
(...skipping 28 matching lines...) Expand all
173 pump_ = MESSAGE_PUMP_IO; 173 pump_ = MESSAGE_PUMP_IO;
174 } else { 174 } else {
175 DCHECK_EQ(TYPE_DEFAULT, type_); 175 DCHECK_EQ(TYPE_DEFAULT, type_);
176 pump_ = new base::MessagePumpDefault(); 176 pump_ = new base::MessagePumpDefault();
177 } 177 }
178 } 178 }
179 179
180 MessageLoop::~MessageLoop() { 180 MessageLoop::~MessageLoop() {
181 DCHECK_EQ(this, current()); 181 DCHECK_EQ(this, current());
182 182
183 DCHECK(!state_); 183 DCHECK(!run_loop_);
184 184
185 // Clean up any unprocessed tasks, but take care: deleting a task could 185 // Clean up any unprocessed tasks, but take care: deleting a task could
186 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 186 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
187 // limit on the number of times we will allow a deleted task to generate more 187 // limit on the number of times we will allow a deleted task to generate more
188 // tasks. Normally, we should only pass through this loop once or twice. If 188 // tasks. Normally, we should only pass through this loop once or twice. If
189 // we end up hitting the loop limit, then it is probably due to one task that 189 // we end up hitting the loop limit, then it is probably due to one task that
190 // is being stubborn. Inspect the queues to see who is left. 190 // is being stubborn. Inspect the queues to see who is left.
191 bool did_work; 191 bool did_work;
192 for (int i = 0; i < 100; ++i) { 192 for (int i = 0; i < 100; ++i) {
193 DeletePendingTasks(); 193 DeletePendingTasks();
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 const tracked_objects::Location& from_here, 286 const tracked_objects::Location& from_here,
287 const base::Closure& task, 287 const base::Closure& task,
288 TimeDelta delay) { 288 TimeDelta delay) {
289 DCHECK(!task.is_null()) << from_here.ToString(); 289 DCHECK(!task.is_null()) << from_here.ToString();
290 PendingTask pending_task( 290 PendingTask pending_task(
291 from_here, task, CalculateDelayedRuntime(delay), false); 291 from_here, task, CalculateDelayedRuntime(delay), false);
292 AddToIncomingQueue(&pending_task); 292 AddToIncomingQueue(&pending_task);
293 } 293 }
294 294
295 void MessageLoop::Run() { 295 void MessageLoop::Run() {
296 AutoRunState save_state(this); 296 base::RunLoop run_loop;
297 RunHandler(); 297 run_loop.Run();
298 } 298 }
299 299
300 void MessageLoop::RunAllPending() { 300 void MessageLoop::RunUntilIdle() {
301 AutoRunState save_state(this); 301 base::RunLoop run_loop;
302 state_->quit_received = true; // Means run until we would otherwise block. 302 run_loop.RunUntilIdle();
303 RunHandler();
304 } 303 }
305 304
306 void MessageLoop::Quit() { 305 void MessageLoop::QuitWhenIdle() {
307 DCHECK_EQ(this, current()); 306 DCHECK_EQ(this, current());
308 if (state_) { 307 if (run_loop_) {
309 state_->quit_received = true; 308 run_loop_->quit_when_idle_received_ = true;
310 } else { 309 } else {
311 NOTREACHED() << "Must be inside Run to call Quit"; 310 NOTREACHED() << "Must be inside Run to call Quit";
312 } 311 }
313 } 312 }
314 313
315 void MessageLoop::QuitNow() { 314 void MessageLoop::QuitNow() {
316 DCHECK_EQ(this, current()); 315 DCHECK_EQ(this, current());
317 if (state_) { 316 if (run_loop_) {
318 pump_->Quit(); 317 pump_->Quit();
319 } else { 318 } else {
320 NOTREACHED() << "Must be inside Run to call Quit"; 319 NOTREACHED() << "Must be inside Run to call Quit";
321 } 320 }
322 } 321 }
323 322
324 static void QuitCurrent() { 323 static void QuitCurrentWhenIdle() {
325 MessageLoop::current()->Quit(); 324 MessageLoop::current()->QuitWhenIdle();
326 } 325 }
327 326
328 // static 327 // static
329 base::Closure MessageLoop::QuitClosure() { 328 base::Closure MessageLoop::QuitWhenIdleClosure() {
330 return base::Bind(&QuitCurrent); 329 return base::Bind(&QuitCurrentWhenIdle);
331 } 330 }
332 331
333 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 332 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
334 if (nestable_tasks_allowed_ != allowed) { 333 if (nestable_tasks_allowed_ != allowed) {
335 nestable_tasks_allowed_ = allowed; 334 nestable_tasks_allowed_ = allowed;
336 if (!nestable_tasks_allowed_) 335 if (!nestable_tasks_allowed_)
337 return; 336 return;
338 // Start the native pump if we are not already pumping. 337 // Start the native pump if we are not already pumping.
339 pump_->ScheduleWork(); 338 pump_->ScheduleWork();
340 } 339 }
341 } 340 }
342 341
343 bool MessageLoop::NestableTasksAllowed() const { 342 bool MessageLoop::NestableTasksAllowed() const {
344 return nestable_tasks_allowed_; 343 return nestable_tasks_allowed_;
345 } 344 }
346 345
347 bool MessageLoop::IsNested() { 346 bool MessageLoop::IsNested() {
348 return state_->run_depth > 1; 347 return run_loop_->run_depth_ > 1;
349 } 348 }
350 349
351 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 350 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
352 DCHECK_EQ(this, current()); 351 DCHECK_EQ(this, current());
353 task_observers_.AddObserver(task_observer); 352 task_observers_.AddObserver(task_observer);
354 } 353 }
355 354
356 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 355 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
357 DCHECK_EQ(this, current()); 356 DCHECK_EQ(this, current());
358 task_observers_.RemoveObserver(task_observer); 357 task_observers_.RemoveObserver(task_observer);
359 } 358 }
360 359
361 void MessageLoop::AssertIdle() const { 360 void MessageLoop::AssertIdle() const {
362 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. 361 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
363 base::AutoLock lock(incoming_queue_lock_); 362 base::AutoLock lock(incoming_queue_lock_);
364 DCHECK(incoming_queue_.empty()); 363 DCHECK(incoming_queue_.empty());
365 } 364 }
366 365
367 bool MessageLoop::is_running() const { 366 bool MessageLoop::is_running() const {
368 DCHECK_EQ(this, current()); 367 DCHECK_EQ(this, current());
369 return state_ != NULL; 368 return !!run_loop_;
jar (doing other things) 2012/06/23 02:43:19 nit: I couldn't find it... but I think the style g
jbates 2012/06/25 20:04:57 Done.
370 } 369 }
371 370
372 //------------------------------------------------------------------------------ 371 //------------------------------------------------------------------------------
373 372
374 // Runs the loop in two different SEH modes: 373 // Runs the loop in two different SEH modes:
375 // enable_SEH_restoration_ = false : any unhandled exception goes to the last 374 // enable_SEH_restoration_ = false : any unhandled exception goes to the last
376 // one that calls SetUnhandledExceptionFilter(). 375 // one that calls SetUnhandledExceptionFilter().
377 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter 376 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter
378 // that was existed before the loop was run. 377 // that was existed before the loop was run.
379 void MessageLoop::RunHandler() { 378 void MessageLoop::RunHandler() {
(...skipping 17 matching lines...) Expand all
397 return; 396 return;
398 } 397 }
399 #endif 398 #endif
400 399
401 void MessageLoop::RunInternal() { 400 void MessageLoop::RunInternal() {
402 DCHECK_EQ(this, current()); 401 DCHECK_EQ(this, current());
403 402
404 StartHistogrammer(); 403 StartHistogrammer();
405 404
406 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 405 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
407 if (state_->dispatcher && type() == TYPE_UI) { 406 if (run_loop_->dispatcher_ && type() == TYPE_UI) {
408 static_cast<base::MessagePumpForUI*>(pump_.get())-> 407 static_cast<base::MessagePumpForUI*>(pump_.get())->
409 RunWithDispatcher(this, state_->dispatcher); 408 RunWithDispatcher(this, run_loop_->dispatcher_);
410 return; 409 return;
411 } 410 }
412 #endif 411 #endif
413 412
414 pump_->Run(this); 413 pump_->Run(this);
415 } 414 }
416 415
417 bool MessageLoop::ProcessNextDelayedNonNestableTask() { 416 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
418 if (state_->run_depth != 1)
419 return false;
420
421 if (deferred_non_nestable_work_queue_.empty()) 417 if (deferred_non_nestable_work_queue_.empty())
422 return false; 418 return false;
423 419
420 if (run_loop_->run_depth_ != 1)
421 return false;
422
424 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); 423 PendingTask pending_task = deferred_non_nestable_work_queue_.front();
425 deferred_non_nestable_work_queue_.pop(); 424 deferred_non_nestable_work_queue_.pop();
426 425
427 RunTask(pending_task); 426 RunTask(pending_task);
428 return true; 427 return true;
429 } 428 }
430 429
431 void MessageLoop::RunTask(const PendingTask& pending_task) { 430 void MessageLoop::RunTask(const PendingTask& pending_task) {
432 TRACE_EVENT2("task", "MessageLoop::RunTask", 431 TRACE_EVENT2("task", "MessageLoop::RunTask",
433 "src_file", pending_task.posted_from.file_name(), 432 "src_file", pending_task.posted_from.file_name(),
(...skipping 22 matching lines...) Expand all
456 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 455 FOR_EACH_OBSERVER(TaskObserver, task_observers_,
457 DidProcessTask(pending_task.time_posted)); 456 DidProcessTask(pending_task.time_posted));
458 457
459 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, 458 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
460 start_time, tracked_objects::ThreadData::NowForEndOfRun()); 459 start_time, tracked_objects::ThreadData::NowForEndOfRun());
461 460
462 nestable_tasks_allowed_ = true; 461 nestable_tasks_allowed_ = true;
463 } 462 }
464 463
465 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 464 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
466 if (pending_task.nestable || state_->run_depth == 1) { 465 if (pending_task.nestable || run_loop_->run_depth_ == 1) {
467 RunTask(pending_task); 466 RunTask(pending_task);
468 // Show that we ran a task (Note: a new one might arrive as a 467 // Show that we ran a task (Note: a new one might arrive as a
469 // consequence!). 468 // consequence!).
470 return true; 469 return true;
471 } 470 }
472 471
473 // We couldn't run the task now because we're in a nested message loop 472 // We couldn't run the task now because we're in a nested message loop
474 // and the task isn't nestable. 473 // and the task isn't nestable.
475 deferred_non_nestable_work_queue_.push(pending_task); 474 deferred_non_nestable_work_queue_.push(pending_task);
476 return false; 475 return false;
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 if (!delayed_work_queue_.empty()) 677 if (!delayed_work_queue_.empty())
679 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 678 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
680 679
681 return DeferOrRunPendingTask(pending_task); 680 return DeferOrRunPendingTask(pending_task);
682 } 681 }
683 682
684 bool MessageLoop::DoIdleWork() { 683 bool MessageLoop::DoIdleWork() {
685 if (ProcessNextDelayedNonNestableTask()) 684 if (ProcessNextDelayedNonNestableTask())
686 return true; 685 return true;
687 686
688 if (state_->quit_received) 687 if (run_loop_->quit_when_idle_received_)
689 pump_->Quit(); 688 pump_->Quit();
690 689
691 return false; 690 return false;
692 } 691 }
693 692
694 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, 693 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
695 void(*deleter)(const void*), 694 void(*deleter)(const void*),
696 const void* object) { 695 const void* object) {
697 PostNonNestableTask(from_here, base::Bind(deleter, object)); 696 PostNonNestableTask(from_here, base::Bind(deleter, object));
698 } 697 }
699 698
700 void MessageLoop::ReleaseSoonInternal( 699 void MessageLoop::ReleaseSoonInternal(
701 const tracked_objects::Location& from_here, 700 const tracked_objects::Location& from_here,
702 void(*releaser)(const void*), 701 void(*releaser)(const void*),
703 const void* object) { 702 const void* object) {
704 PostNonNestableTask(from_here, base::Bind(releaser, object)); 703 PostNonNestableTask(from_here, base::Bind(releaser, object));
705 } 704 }
706 705
707 //------------------------------------------------------------------------------ 706 //------------------------------------------------------------------------------
708 // MessageLoop::AutoRunState
709
710 MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
711 // Make the loop reference us.
712 previous_state_ = loop_->state_;
713 if (previous_state_) {
714 run_depth = previous_state_->run_depth + 1;
715 } else {
716 run_depth = 1;
717 }
718 loop_->state_ = this;
719
720 // Initialize the other fields:
721 quit_received = false;
722 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
723 dispatcher = NULL;
724 #endif
725 }
726
727 MessageLoop::AutoRunState::~AutoRunState() {
728 loop_->state_ = previous_state_;
729 }
730
731 //------------------------------------------------------------------------------
732 // MessageLoopForUI 707 // MessageLoopForUI
733 708
734 #if defined(OS_WIN) 709 #if defined(OS_WIN)
735 void MessageLoopForUI::DidProcessMessage(const MSG& message) { 710 void MessageLoopForUI::DidProcessMessage(const MSG& message) {
736 pump_win()->DidProcessMessage(message); 711 pump_win()->DidProcessMessage(message);
737 } 712 }
738 #endif // defined(OS_WIN) 713 #endif // defined(OS_WIN)
739 714
740 #if defined(OS_ANDROID) 715 #if defined(OS_ANDROID)
741 void MessageLoopForUI::Start() { 716 void MessageLoopForUI::Start() {
742 // No Histogram support for UI message loop as it is managed by Java side 717 // No Histogram support for UI message loop as it is managed by Java side
743 static_cast<base::MessagePumpForUI*>(pump_.get())->Start(this); 718 static_cast<base::MessagePumpForUI*>(pump_.get())->Start(this);
744 } 719 }
745 #endif 720 #endif
746 721
747 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 722 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
748 void MessageLoopForUI::AddObserver(Observer* observer) { 723 void MessageLoopForUI::AddObserver(Observer* observer) {
749 pump_ui()->AddObserver(observer); 724 pump_ui()->AddObserver(observer);
750 } 725 }
751 726
752 void MessageLoopForUI::RemoveObserver(Observer* observer) { 727 void MessageLoopForUI::RemoveObserver(Observer* observer) {
753 pump_ui()->RemoveObserver(observer); 728 pump_ui()->RemoveObserver(observer);
754 } 729 }
755 730
756 void MessageLoopForUI::RunWithDispatcher(Dispatcher* dispatcher) {
757 AutoRunState save_state(this);
758 state_->dispatcher = dispatcher;
759 RunHandler();
760 }
761
762 void MessageLoopForUI::RunAllPendingWithDispatcher(Dispatcher* dispatcher) {
763 AutoRunState save_state(this);
764 state_->dispatcher = dispatcher;
765 state_->quit_received = true; // Means run until we would otherwise block.
766 RunHandler();
767 }
768
769 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 731 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
770 732
771 //------------------------------------------------------------------------------ 733 //------------------------------------------------------------------------------
772 // MessageLoopForIO 734 // MessageLoopForIO
773 735
774 #if defined(OS_WIN) 736 #if defined(OS_WIN)
775 737
776 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 738 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
777 pump_io()->RegisterIOHandler(file, handler); 739 pump_io()->RegisterIOHandler(file, handler);
778 } 740 }
(...skipping 11 matching lines...) Expand all
790 Watcher *delegate) { 752 Watcher *delegate) {
791 return pump_libevent()->WatchFileDescriptor( 753 return pump_libevent()->WatchFileDescriptor(
792 fd, 754 fd,
793 persistent, 755 persistent,
794 static_cast<base::MessagePumpLibevent::Mode>(mode), 756 static_cast<base::MessagePumpLibevent::Mode>(mode),
795 controller, 757 controller,
796 delegate); 758 delegate);
797 } 759 }
798 760
799 #endif 761 #endif
OLDNEW
« no previous file with comments | « base/message_loop.h ('k') | base/message_loop_unittest.cc » ('j') | base/message_pump_android.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698