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 3 // found in the LICENSE file. 4 5 #include "base/message_loop/message_loop.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/compiler_specific.h" 11 #include "base/debug/alias.h" 12 #include "base/debug/trace_event.h" 13 #include "base/lazy_instance.h" 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/message_loop/message_pump_default.h" 17 #include "base/metrics/histogram.h" 18 #include "base/metrics/statistics_recorder.h" 19 #include "base/run_loop.h" 20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 21 #include "base/thread_task_runner_handle.h" 22 #include "base/threading/thread_local.h" 23 #include "base/time/time.h" 24 #include "base/tracked_objects.h" 25 26 #if defined(OS_MACOSX) 27 #include "base/message_loop/message_pump_mac.h" 28 #endif 29 #if defined(OS_POSIX) && !defined(OS_IOS) 30 #include "base/message_loop/message_pump_libevent.h" 31 #endif 32 #if defined(OS_ANDROID) 33 #include "base/message_loop/message_pump_android.h" 34 #endif 35 36 #if defined(TOOLKIT_GTK) 37 #include <gdk/gdk.h> 38 #include <gdk/gdkx.h> 39 #endif 40 41 namespace base { 42 43 namespace { 44 45 // A lazily created thread local storage for quick access to a thread's message 46 // loop, if one exists. This should be safe and free of static constructors. 47 LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr = 48 LAZY_INSTANCE_INITIALIZER; 49 50 // Logical events for Histogram profiling. Run with -message-loop-histogrammer 51 // to get an accounting of messages and actions taken on each thread. 52 const int kTaskRunEvent = 0x1; 53 const int kTimerEvent = 0x2; 54 55 // Provide range of message IDs for use in histogramming and debug display. 56 const int kLeastNonZeroMessageId = 1; 57 const int kMaxMessageId = 1099; 58 const int kNumberOfDistinctMessagesDisplayed = 1100; 59 60 // Provide a macro that takes an expression (such as a constant, or macro 61 // constant) and creates a pair to initalize an array of pairs. In this case, 62 // our pair consists of the expressions value, and the "stringized" version 63 // of the expression (i.e., the exrpression put in quotes). For example, if 64 // we have: 65 // #define FOO 2 66 // #define BAR 5 67 // then the following: 68 // VALUE_TO_NUMBER_AND_NAME(FOO + BAR) 69 // will expand to: 70 // {7, "FOO + BAR"} 71 // We use the resulting array as an argument to our histogram, which reads the 72 // number as a bucket identifier, and proceeds to use the corresponding name 73 // in the pair (i.e., the quoted string) when printing out a histogram. 74 #define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, 75 76 const LinearHistogram::DescriptionPair event_descriptions_[] = { 77 // Provide some pretty print capability in our histogram for our internal 78 // messages. 79 80 // A few events we handle (kindred to messages), and used to profile actions. 81 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) 82 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) 83 84 {-1, NULL} // The list must be null terminated, per API to histogram. 85 }; 86 87 bool enable_histogrammer_ = false; 88 89 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; 90 91 // Returns true if MessagePump::ScheduleWork() must be called one 92 // time for every task that is added to the MessageLoop incoming queue. 93 bool AlwaysNotifyPump(MessageLoop::Type type) { 94 #if defined(OS_ANDROID) 95 return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA; 96 #else 97 return false; 98 #endif 99 } 100 101 } // namespace 102 103 //------------------------------------------------------------------------------ 104 105 #if defined(OS_WIN) 106 107 // Upon a SEH exception in this thread, it restores the original unhandled 108 // exception filter. 109 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 110 ::SetUnhandledExceptionFilter(old_filter); 111 return EXCEPTION_CONTINUE_SEARCH; 112 } 113 114 // Retrieves a pointer to the current unhandled exception filter. There 115 // is no standalone getter method. 116 static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { 117 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; 118 top_filter = ::SetUnhandledExceptionFilter(0); 119 ::SetUnhandledExceptionFilter(top_filter); 120 return top_filter; 121 } 122 123 #endif // defined(OS_WIN) 124 125 //------------------------------------------------------------------------------ 126 127 MessageLoop::TaskObserver::TaskObserver() { 128 } 129 130 MessageLoop::TaskObserver::~TaskObserver() { 131 } 132 133 MessageLoop::DestructionObserver::~DestructionObserver() { 134 } 135 136 //------------------------------------------------------------------------------ 137 138 MessageLoop::MessageLoop(Type type) 139 : type_(type), 140 exception_restoration_(false), 141 nestable_tasks_allowed_(true), 142 #if defined(OS_WIN) 143 os_modal_loop_(false), 144 #endif // OS_WIN 145 message_histogram_(NULL), 146 run_loop_(NULL) { 147 DCHECK(!current()) << "should only have one message loop per thread"; 148 lazy_tls_ptr.Pointer()->Set(this); 149 150 incoming_task_queue_ = new internal::IncomingTaskQueue(this); 151 message_loop_proxy_ = 152 new internal::MessageLoopProxyImpl(incoming_task_queue_); 153 thread_task_runner_handle_.reset( 154 new ThreadTaskRunnerHandle(message_loop_proxy_)); 155 156 // TODO(rvargas): Get rid of the OS guards. 157 #if defined(OS_WIN) 158 #define MESSAGE_PUMP_UI new MessagePumpForUI() 159 #define MESSAGE_PUMP_IO new MessagePumpForIO() 160 #elif defined(OS_IOS) 161 #define MESSAGE_PUMP_UI MessagePumpMac::Create() 162 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() 163 #elif defined(OS_MACOSX) 164 #define MESSAGE_PUMP_UI MessagePumpMac::Create() 165 #define MESSAGE_PUMP_IO new MessagePumpLibevent() 166 #elif defined(OS_NACL) 167 // Currently NaCl doesn't have a UI MessageLoop. 168 // TODO(abarth): Figure out if we need this. 169 #define MESSAGE_PUMP_UI NULL 170 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and 171 // doesn't require extra support for watching file descriptors. 172 #define MESSAGE_PUMP_IO new MessagePumpDefault() 173 #elif defined(OS_POSIX) // POSIX but not MACOSX. 174 #define MESSAGE_PUMP_UI new MessagePumpForUI() 175 #define MESSAGE_PUMP_IO new MessagePumpLibevent() 176 #else 177 #error Not implemented 178 #endif 179 180 if (type_ == TYPE_UI) { 181 if (message_pump_for_ui_factory_) 182 pump_.reset(message_pump_for_ui_factory_()); 183 else 184 pump_.reset(MESSAGE_PUMP_UI); 185 } else if (type_ == TYPE_IO) { 186 pump_.reset(MESSAGE_PUMP_IO); 187 #if defined(OS_ANDROID) 188 } else if (type_ == TYPE_JAVA) { 189 pump_.reset(MESSAGE_PUMP_UI); 190 #endif 191 } else { 192 DCHECK_EQ(TYPE_DEFAULT, type_); 193 pump_.reset(new MessagePumpDefault()); 194 } 195 } 196 197 MessageLoop::~MessageLoop() { 198 DCHECK_EQ(this, current()); 199 200 DCHECK(!run_loop_); 201 202 // Clean up any unprocessed tasks, but take care: deleting a task could 203 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 204 // limit on the number of times we will allow a deleted task to generate more 205 // tasks. Normally, we should only pass through this loop once or twice. If 206 // we end up hitting the loop limit, then it is probably due to one task that 207 // is being stubborn. Inspect the queues to see who is left. 208 bool did_work; 209 for (int i = 0; i < 100; ++i) { 210 DeletePendingTasks(); 211 ReloadWorkQueue(); 212 // If we end up with empty queues, then break out of the loop. 213 did_work = DeletePendingTasks(); 214 if (!did_work) 215 break; 216 } 217 DCHECK(!did_work); 218 219 // Let interested parties have one last shot at accessing this. 220 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 221 WillDestroyCurrentMessageLoop()); 222 223 thread_task_runner_handle_.reset(); 224 225 // Tell the incoming queue that we are dying. 226 incoming_task_queue_->WillDestroyCurrentMessageLoop(); 227 incoming_task_queue_ = NULL; 228 message_loop_proxy_ = NULL; 229 230 // OK, now make it so that no one can find us. 231 lazy_tls_ptr.Pointer()->Set(NULL); 232 } 233 234 // static 235 MessageLoop* MessageLoop::current() { 236 // TODO(darin): sadly, we cannot enable this yet since people call us even 237 // when they have no intention of using us. 238 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; 239 return lazy_tls_ptr.Pointer()->Get(); 240 } 241 242 // static 243 void MessageLoop::EnableHistogrammer(bool enable) { 244 enable_histogrammer_ = enable; 245 } 246 247 // static 248 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { 249 if (message_pump_for_ui_factory_) 250 return false; 251 252 message_pump_for_ui_factory_ = factory; 253 return true; 254 } 255 256 void MessageLoop::AddDestructionObserver( 257 DestructionObserver* destruction_observer) { 258 DCHECK_EQ(this, current()); 259 destruction_observers_.AddObserver(destruction_observer); 260 } 261 262 void MessageLoop::RemoveDestructionObserver( 263 DestructionObserver* destruction_observer) { 264 DCHECK_EQ(this, current()); 265 destruction_observers_.RemoveObserver(destruction_observer); 266 } 267 268 void MessageLoop::PostTask( 269 const tracked_objects::Location& from_here, 270 const Closure& task) { 271 DCHECK(!task.is_null()) << from_here.ToString(); 272 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); 273 } 274 275 bool MessageLoop::TryPostTask( 276 const tracked_objects::Location& from_here, 277 const Closure& task) { 278 DCHECK(!task.is_null()) << from_here.ToString(); 279 return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); 280 } 281 282 void MessageLoop::PostDelayedTask( 283 const tracked_objects::Location& from_here, 284 const Closure& task, 285 TimeDelta delay) { 286 DCHECK(!task.is_null()) << from_here.ToString(); 287 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); 288 } 289 290 void MessageLoop::PostNonNestableTask( 291 const tracked_objects::Location& from_here, 292 const Closure& task) { 293 DCHECK(!task.is_null()) << from_here.ToString(); 294 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); 295 } 296 297 void MessageLoop::PostNonNestableDelayedTask( 298 const tracked_objects::Location& from_here, 299 const Closure& task, 300 TimeDelta delay) { 301 DCHECK(!task.is_null()) << from_here.ToString(); 302 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); 303 } 304 305 void MessageLoop::Run() { 306 RunLoop run_loop; 307 run_loop.Run(); 308 } 309 310 void MessageLoop::RunUntilIdle() { 311 RunLoop run_loop; 312 run_loop.RunUntilIdle(); 313 } 314 315 void MessageLoop::QuitWhenIdle() { 316 DCHECK_EQ(this, current()); 317 if (run_loop_) { 318 run_loop_->quit_when_idle_received_ = true; 319 } else { 320 NOTREACHED() << "Must be inside Run to call Quit"; 321 } 322 } 323 324 void MessageLoop::QuitNow() { 325 DCHECK_EQ(this, current()); 326 if (run_loop_) { 327 pump_->Quit(); 328 } else { 329 NOTREACHED() << "Must be inside Run to call Quit"; 330 } 331 } 332 333 bool MessageLoop::IsType(Type type) const { 334 return type_ == type; 335 } 336 337 static void QuitCurrentWhenIdle() { 338 MessageLoop::current()->QuitWhenIdle(); 339 } 340 341 // static 342 Closure MessageLoop::QuitWhenIdleClosure() { 343 return Bind(&QuitCurrentWhenIdle); 344 } 345 346 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 347 if (nestable_tasks_allowed_ != allowed) { 348 nestable_tasks_allowed_ = allowed; 349 if (!nestable_tasks_allowed_) 350 return; 351 // Start the native pump if we are not already pumping. 352 pump_->ScheduleWork(); 353 } 354 } 355 356 bool MessageLoop::NestableTasksAllowed() const { 357 return nestable_tasks_allowed_; 358 } 359 360 bool MessageLoop::IsNested() { 361 return run_loop_->run_depth_ > 1; 362 } 363 364 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 365 DCHECK_EQ(this, current()); 366 task_observers_.AddObserver(task_observer); 367 } 368 369 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 370 DCHECK_EQ(this, current()); 371 task_observers_.RemoveObserver(task_observer); 372 } 373 374 bool MessageLoop::is_running() const { 375 DCHECK_EQ(this, current()); 376 return run_loop_ != NULL; 377 } 378 379 bool MessageLoop::IsHighResolutionTimerEnabledForTesting() { 380 return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting(); 381 } 382 383 bool MessageLoop::IsIdleForTesting() { 384 // We only check the imcoming queue|, since we don't want to lock the work 385 // queue. 386 return incoming_task_queue_->IsIdleForTesting(); 387 } 388 389 void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait, 390 WaitableEvent* caller_signal) { 391 incoming_task_queue_->LockWaitUnLockForTesting(caller_wait, caller_signal); 392 } 393 394 //------------------------------------------------------------------------------ 395 396 // Runs the loop in two different SEH modes: 397 // enable_SEH_restoration_ = false : any unhandled exception goes to the last 398 // one that calls SetUnhandledExceptionFilter(). 399 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter 400 // that was existed before the loop was run. 401 void MessageLoop::RunHandler() { 402 #if defined(OS_WIN) 403 if (exception_restoration_) { 404 RunInternalInSEHFrame(); 405 return; 406 } 407 #endif 408 409 RunInternal(); 410 } 411 412 #if defined(OS_WIN) 413 __declspec(noinline) void MessageLoop::RunInternalInSEHFrame() { 414 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); 415 __try { 416 RunInternal(); 417 } __except(SEHFilter(current_filter)) { 418 } 419 return; 420 } 421 #endif 422 423 void MessageLoop::RunInternal() { 424 DCHECK_EQ(this, current()); 425 426 StartHistogrammer(); 427 428 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 429 if (run_loop_->dispatcher_ && type() == TYPE_UI) { 430 static_cast<MessagePumpForUI*>(pump_.get())-> 431 RunWithDispatcher(this, run_loop_->dispatcher_); 432 return; 433 } 434 #endif 435 436 pump_->Run(this); 437 } 438 439 bool MessageLoop::ProcessNextDelayedNonNestableTask() { 440 if (run_loop_->run_depth_ != 1) 441 return false; 442 443 if (deferred_non_nestable_work_queue_.empty()) 444 return false; 445 446 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); 447 deferred_non_nestable_work_queue_.pop(); 448 449 RunTask(pending_task); 450 return true; 451 } 452 453 void MessageLoop::RunTask(const PendingTask& pending_task) { 454 tracked_objects::TrackedTime start_time = 455 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); 456 457 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", 458 TRACE_ID_MANGLE(GetTaskTraceID(pending_task)), 459 "queue_duration", 460 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); 461 TRACE_EVENT2("task", "MessageLoop::RunTask", 462 "src_file", pending_task.posted_from.file_name(), 463 "src_func", pending_task.posted_from.function_name()); 464 465 DCHECK(nestable_tasks_allowed_); 466 // Execute the task and assume the worst: It is probably not reentrant. 467 nestable_tasks_allowed_ = false; 468 469 // Before running the task, store the program counter where it was posted 470 // and deliberately alias it to ensure it is on the stack if the task 471 // crashes. Be careful not to assume that the variable itself will have the 472 // expected value when displayed by the optimizer in an optimized build. 473 // Look at a memory dump of the stack. 474 const void* program_counter = 475 pending_task.posted_from.program_counter(); 476 debug::Alias(&program_counter); 477 478 HistogramEvent(kTaskRunEvent); 479 480 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 481 WillProcessTask(pending_task)); 482 pending_task.task.Run(); 483 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 484 DidProcessTask(pending_task)); 485 486 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, 487 start_time, tracked_objects::ThreadData::NowForEndOfRun()); 488 489 nestable_tasks_allowed_ = true; 490 } 491 492 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 493 if (pending_task.nestable || run_loop_->run_depth_ == 1) { 494 RunTask(pending_task); 495 // Show that we ran a task (Note: a new one might arrive as a 496 // consequence!). 497 return true; 498 } 499 500 // We couldn't run the task now because we're in a nested message loop 501 // and the task isn't nestable. 502 deferred_non_nestable_work_queue_.push(pending_task); 503 return false; 504 } 505 506 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 507 // Move to the delayed work queue. 508 delayed_work_queue_.push(pending_task); 509 } 510 511 bool MessageLoop::DeletePendingTasks() { 512 bool did_work = !work_queue_.empty(); 513 while (!work_queue_.empty()) { 514 PendingTask pending_task = work_queue_.front(); 515 work_queue_.pop(); 516 if (!pending_task.delayed_run_time.is_null()) { 517 // We want to delete delayed tasks in the same order in which they would 518 // normally be deleted in case of any funny dependencies between delayed 519 // tasks. 520 AddToDelayedWorkQueue(pending_task); 521 } 522 } 523 did_work |= !deferred_non_nestable_work_queue_.empty(); 524 while (!deferred_non_nestable_work_queue_.empty()) { 525 deferred_non_nestable_work_queue_.pop(); 526 } 527 did_work |= !delayed_work_queue_.empty(); 528 529 // Historically, we always delete the task regardless of valgrind status. It's 530 // not completely clear why we want to leak them in the loops above. This 531 // code is replicating legacy behavior, and should not be considered 532 // absolutely "correct" behavior. See TODO above about deleting all tasks 533 // when it's safe. 534 while (!delayed_work_queue_.empty()) { 535 delayed_work_queue_.pop(); 536 } 537 return did_work; 538 } 539 540 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { 541 return (static_cast<uint64>(task.sequence_num) << 32) | 542 static_cast<uint64>(reinterpret_cast<intptr_t>(this)); 543 } 544 545 void MessageLoop::ReloadWorkQueue() { 546 // We can improve performance of our loading tasks from the incoming queue to 547 // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to 548 // load. That reduces the number of locks-per-task significantly when our 549 // queues get large. 550 if (work_queue_.empty()) 551 incoming_task_queue_->ReloadWorkQueue(&work_queue_); 552 } 553 554 void MessageLoop::ScheduleWork(bool was_empty) { 555 // The Android UI message loop needs to get notified each time 556 // a task is added to the incoming queue. 557 if (was_empty || AlwaysNotifyPump(type_)) 558 pump_->ScheduleWork(); 559 } 560 561 //------------------------------------------------------------------------------ 562 // Method and data for histogramming events and actions taken by each instance 563 // on each thread. 564 565 void MessageLoop::StartHistogrammer() { 566 #if !defined(OS_NACL) // NaCl build has no metrics code. 567 if (enable_histogrammer_ && !message_histogram_ 568 && StatisticsRecorder::IsActive()) { 569 DCHECK(!thread_name_.empty()); 570 message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription( 571 "MsgLoop:" + thread_name_, 572 kLeastNonZeroMessageId, kMaxMessageId, 573 kNumberOfDistinctMessagesDisplayed, 574 message_histogram_->kHexRangePrintingFlag, 575 event_descriptions_); 576 } 577 #endif 578 } 579 580 void MessageLoop::HistogramEvent(int event) { 581 #if !defined(OS_NACL) 582 if (message_histogram_) 583 message_histogram_->Add(event); 584 #endif 585 } 586 587 bool MessageLoop::DoWork() { 588 if (!nestable_tasks_allowed_) { 589 // Task can't be executed right now. 590 return false; 591 } 592 593 for (;;) { 594 ReloadWorkQueue(); 595 if (work_queue_.empty()) 596 break; 597 598 // Execute oldest task. 599 do { 600 PendingTask pending_task = work_queue_.front(); 601 work_queue_.pop(); 602 if (!pending_task.delayed_run_time.is_null()) { 603 AddToDelayedWorkQueue(pending_task); 604 // If we changed the topmost task, then it is time to reschedule. 605 if (delayed_work_queue_.top().task.Equals(pending_task.task)) 606 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 607 } else { 608 if (DeferOrRunPendingTask(pending_task)) 609 return true; 610 } 611 } while (!work_queue_.empty()); 612 } 613 614 // Nothing happened. 615 return false; 616 } 617 618 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { 619 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 620 recent_time_ = *next_delayed_work_time = TimeTicks(); 621 return false; 622 } 623 624 // When we "fall behind," there will be a lot of tasks in the delayed work 625 // queue that are ready to run. To increase efficiency when we fall behind, 626 // we will only call Time::Now() intermittently, and then process all tasks 627 // that are ready to run before calling it again. As a result, the more we 628 // fall behind (and have a lot of ready-to-run delayed tasks), the more 629 // efficient we'll be at handling the tasks. 630 631 TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time; 632 if (next_run_time > recent_time_) { 633 recent_time_ = TimeTicks::Now(); // Get a better view of Now(); 634 if (next_run_time > recent_time_) { 635 *next_delayed_work_time = next_run_time; 636 return false; 637 } 638 } 639 640 PendingTask pending_task = delayed_work_queue_.top(); 641 delayed_work_queue_.pop(); 642 643 if (!delayed_work_queue_.empty()) 644 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 645 646 return DeferOrRunPendingTask(pending_task); 647 } 648 649 bool MessageLoop::DoIdleWork() { 650 if (ProcessNextDelayedNonNestableTask()) 651 return true; 652 653 if (run_loop_->quit_when_idle_received_) 654 pump_->Quit(); 655 656 return false; 657 } 658 659 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, 660 void(*deleter)(const void*), 661 const void* object) { 662 PostNonNestableTask(from_here, Bind(deleter, object)); 663 } 664 665 void MessageLoop::ReleaseSoonInternal( 666 const tracked_objects::Location& from_here, 667 void(*releaser)(const void*), 668 const void* object) { 669 PostNonNestableTask(from_here, Bind(releaser, object)); 670 } 671 672 //------------------------------------------------------------------------------ 673 // MessageLoopForUI 674 675 #if defined(OS_WIN) 676 void MessageLoopForUI::DidProcessMessage(const MSG& message) { 677 pump_win()->DidProcessMessage(message); 678 } 679 #endif // defined(OS_WIN) 680 681 #if defined(OS_ANDROID) 682 void MessageLoopForUI::Start() { 683 // No Histogram support for UI message loop as it is managed by Java side 684 static_cast<MessagePumpForUI*>(pump_.get())->Start(this); 685 } 686 #endif 687 688 #if defined(OS_IOS) 689 void MessageLoopForUI::Attach() { 690 static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); 691 } 692 #endif 693 694 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 695 void MessageLoopForUI::AddObserver(Observer* observer) { 696 pump_ui()->AddObserver(observer); 697 } 698 699 void MessageLoopForUI::RemoveObserver(Observer* observer) { 700 pump_ui()->RemoveObserver(observer); 701 } 702 703 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 704 705 //------------------------------------------------------------------------------ 706 // MessageLoopForIO 707 708 #if defined(OS_WIN) 709 710 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 711 pump_io()->RegisterIOHandler(file, handler); 712 } 713 714 bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) { 715 return pump_io()->RegisterJobObject(job, handler); 716 } 717 718 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 719 return pump_io()->WaitForIOCompletion(timeout, filter); 720 } 721 722 #elif defined(OS_IOS) 723 724 bool MessageLoopForIO::WatchFileDescriptor(int fd, 725 bool persistent, 726 Mode mode, 727 FileDescriptorWatcher *controller, 728 Watcher *delegate) { 729 return pump_io()->WatchFileDescriptor( 730 fd, 731 persistent, 732 mode, 733 controller, 734 delegate); 735 } 736 737 #elif defined(OS_POSIX) && !defined(OS_NACL) 738 739 bool MessageLoopForIO::WatchFileDescriptor(int fd, 740 bool persistent, 741 Mode mode, 742 FileDescriptorWatcher *controller, 743 Watcher *delegate) { 744 return pump_libevent()->WatchFileDescriptor( 745 fd, 746 persistent, 747 mode, 748 controller, 749 delegate); 750 } 751 752 #endif 753 754 } // namespace base 755