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 #include <utility> 9 10 #include "base/bind.h" 11 #include "base/compiler_specific.h" 12 #include "base/lazy_instance.h" 13 #include "base/logging.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/message_loop/message_pump_default.h" 16 #include "base/metrics/histogram.h" 17 #include "base/metrics/statistics_recorder.h" 18 #include "base/run_loop.h" 19 #include "base/thread_task_runner_handle.h" 20 #include "base/threading/thread_local.h" 21 #include "base/time/time.h" 22 #include "base/trace_event/trace_event.h" 23 #include "base/tracked_objects.h" 24 #include "build/build_config.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 #if defined(USE_GLIB) 36 #include "base/message_loop/message_pump_glib.h" 37 #endif 38 39 namespace base { 40 41 namespace { 42 43 // A lazily created thread local storage for quick access to a thread's message 44 // loop, if one exists. This should be safe and free of static constructors. 45 LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr = 46 LAZY_INSTANCE_INITIALIZER; 47 48 // Logical events for Histogram profiling. Run with --message-loop-histogrammer 49 // to get an accounting of messages and actions taken on each thread. 50 const int kTaskRunEvent = 0x1; 51 #if !defined(OS_NACL) 52 const int kTimerEvent = 0x2; 53 54 // Provide range of message IDs for use in histogramming and debug display. 55 const int kLeastNonZeroMessageId = 1; 56 const int kMaxMessageId = 1099; 57 const int kNumberOfDistinctMessagesDisplayed = 1100; 58 59 // Provide a macro that takes an expression (such as a constant, or macro 60 // constant) and creates a pair to initialize an array of pairs. In this case, 61 // our pair consists of the expressions value, and the "stringized" version 62 // of the expression (i.e., the expression put in quotes). For example, if 63 // we have: 64 // #define FOO 2 65 // #define BAR 5 66 // then the following: 67 // VALUE_TO_NUMBER_AND_NAME(FOO + BAR) 68 // will expand to: 69 // {7, "FOO + BAR"} 70 // We use the resulting array as an argument to our histogram, which reads the 71 // number as a bucket identifier, and proceeds to use the corresponding name 72 // in the pair (i.e., the quoted string) when printing out a histogram. 73 #define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, 74 75 const LinearHistogram::DescriptionPair event_descriptions_[] = { 76 // Provide some pretty print capability in our histogram for our internal 77 // messages. 78 79 // A few events we handle (kindred to messages), and used to profile actions. 80 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) 81 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) 82 83 {-1, NULL} // The list must be null-terminated, per API to histogram. 84 }; 85 #endif // !defined(OS_NACL) 86 87 bool enable_histogrammer_ = false; 88 89 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; 90 91 #if defined(OS_IOS) 92 typedef MessagePumpIOSForIO MessagePumpForIO; 93 #elif defined(OS_NACL_SFI) 94 typedef MessagePumpDefault MessagePumpForIO; 95 #elif defined(OS_POSIX) 96 typedef MessagePumpLibevent MessagePumpForIO; 97 #endif 98 99 #if !defined(OS_NACL_SFI) 100 MessagePumpForIO* ToPumpIO(MessagePump* pump) { 101 return static_cast<MessagePumpForIO*>(pump); 102 } 103 #endif // !defined(OS_NACL_SFI) 104 105 scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) { 106 return pump; 107 } 108 109 } // namespace 110 111 //------------------------------------------------------------------------------ 112 113 MessageLoop::TaskObserver::TaskObserver() { 114 } 115 116 MessageLoop::TaskObserver::~TaskObserver() { 117 } 118 119 MessageLoop::DestructionObserver::~DestructionObserver() { 120 } 121 122 //------------------------------------------------------------------------------ 123 124 MessageLoop::MessageLoop(Type type) 125 : MessageLoop(type, MessagePumpFactoryCallback()) { 126 BindToCurrentThread(); 127 } 128 129 MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump) 130 : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) { 131 BindToCurrentThread(); 132 } 133 134 MessageLoop::~MessageLoop() { 135 // If |pump_| is non-null, this message loop has been bound and should be the 136 // current one on this thread. Otherwise, this loop is being destructed before 137 // it was bound to a thread, so a different message loop (or no loop at all) 138 // may be current. 139 DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); 140 141 // iOS just attaches to the loop, it doesn't Run it. 142 // TODO(stuartmorgan): Consider wiring up a Detach(). 143 #if !defined(OS_IOS) 144 DCHECK(!run_loop_); 145 #endif 146 147 #if defined(OS_WIN) 148 if (in_high_res_mode_) 149 Time::ActivateHighResolutionTimer(false); 150 #endif 151 // Clean up any unprocessed tasks, but take care: deleting a task could 152 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 153 // limit on the number of times we will allow a deleted task to generate more 154 // tasks. Normally, we should only pass through this loop once or twice. If 155 // we end up hitting the loop limit, then it is probably due to one task that 156 // is being stubborn. Inspect the queues to see who is left. 157 bool did_work; 158 for (int i = 0; i < 100; ++i) { 159 DeletePendingTasks(); 160 ReloadWorkQueue(); 161 // If we end up with empty queues, then break out of the loop. 162 did_work = DeletePendingTasks(); 163 if (!did_work) 164 break; 165 } 166 DCHECK(!did_work); 167 168 // Let interested parties have one last shot at accessing this. 169 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 170 WillDestroyCurrentMessageLoop()); 171 172 thread_task_runner_handle_.reset(); 173 174 // Tell the incoming queue that we are dying. 175 incoming_task_queue_->WillDestroyCurrentMessageLoop(); 176 incoming_task_queue_ = NULL; 177 unbound_task_runner_ = NULL; 178 task_runner_ = NULL; 179 180 // OK, now make it so that no one can find us. 181 if (current() == this) 182 lazy_tls_ptr.Pointer()->Set(nullptr); 183 } 184 185 // static 186 MessageLoop* MessageLoop::current() { 187 // TODO(darin): sadly, we cannot enable this yet since people call us even 188 // when they have no intention of using us. 189 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; 190 return lazy_tls_ptr.Pointer()->Get(); 191 } 192 193 // static 194 void MessageLoop::EnableHistogrammer(bool enable) { 195 enable_histogrammer_ = enable; 196 } 197 198 // static 199 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { 200 if (message_pump_for_ui_factory_) 201 return false; 202 203 message_pump_for_ui_factory_ = factory; 204 return true; 205 } 206 207 // static 208 scoped_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) { 209 // TODO(rvargas): Get rid of the OS guards. 210 #if defined(USE_GLIB) && !defined(OS_NACL) 211 typedef MessagePumpGlib MessagePumpForUI; 212 #elif defined(OS_LINUX) && !defined(OS_NACL) 213 typedef MessagePumpLibevent MessagePumpForUI; 214 #endif 215 216 #if defined(OS_IOS) || defined(OS_MACOSX) 217 #define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(MessagePumpMac::Create()) 218 #elif defined(OS_NACL) 219 // Currently NaCl doesn't have a UI MessageLoop. 220 // TODO(abarth): Figure out if we need this. 221 #define MESSAGE_PUMP_UI scoped_ptr<MessagePump>() 222 #else 223 #define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(new MessagePumpForUI()) 224 #endif 225 226 #if defined(OS_MACOSX) 227 // Use an OS native runloop on Mac to support timer coalescing. 228 #define MESSAGE_PUMP_DEFAULT \ 229 scoped_ptr<MessagePump>(new MessagePumpCFRunLoop()) 230 #else 231 #define MESSAGE_PUMP_DEFAULT scoped_ptr<MessagePump>(new MessagePumpDefault()) 232 #endif 233 234 if (type == MessageLoop::TYPE_UI) { 235 if (message_pump_for_ui_factory_) 236 return message_pump_for_ui_factory_(); 237 return MESSAGE_PUMP_UI; 238 } 239 if (type == MessageLoop::TYPE_IO) 240 return scoped_ptr<MessagePump>(new MessagePumpForIO()); 241 242 #if defined(OS_ANDROID) 243 if (type == MessageLoop::TYPE_JAVA) 244 return scoped_ptr<MessagePump>(new MessagePumpForUI()); 245 #endif 246 247 DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type); 248 return MESSAGE_PUMP_DEFAULT; 249 } 250 251 void MessageLoop::AddDestructionObserver( 252 DestructionObserver* destruction_observer) { 253 DCHECK_EQ(this, current()); 254 destruction_observers_.AddObserver(destruction_observer); 255 } 256 257 void MessageLoop::RemoveDestructionObserver( 258 DestructionObserver* destruction_observer) { 259 DCHECK_EQ(this, current()); 260 destruction_observers_.RemoveObserver(destruction_observer); 261 } 262 263 void MessageLoop::PostTask( 264 const tracked_objects::Location& from_here, 265 const Closure& task) { 266 task_runner_->PostTask(from_here, task); 267 } 268 269 void MessageLoop::PostDelayedTask( 270 const tracked_objects::Location& from_here, 271 const Closure& task, 272 TimeDelta delay) { 273 task_runner_->PostDelayedTask(from_here, task, delay); 274 } 275 276 void MessageLoop::PostNonNestableTask( 277 const tracked_objects::Location& from_here, 278 const Closure& task) { 279 task_runner_->PostNonNestableTask(from_here, task); 280 } 281 282 void MessageLoop::PostNonNestableDelayedTask( 283 const tracked_objects::Location& from_here, 284 const Closure& task, 285 TimeDelta delay) { 286 task_runner_->PostNonNestableDelayedTask(from_here, task, delay); 287 } 288 289 void MessageLoop::Run() { 290 DCHECK(pump_); 291 RunLoop run_loop; 292 run_loop.Run(); 293 } 294 295 void MessageLoop::RunUntilIdle() { 296 DCHECK(pump_); 297 RunLoop run_loop; 298 run_loop.RunUntilIdle(); 299 } 300 301 void MessageLoop::QuitWhenIdle() { 302 DCHECK_EQ(this, current()); 303 if (run_loop_) { 304 run_loop_->quit_when_idle_received_ = true; 305 } else { 306 NOTREACHED() << "Must be inside Run to call Quit"; 307 } 308 } 309 310 void MessageLoop::QuitNow() { 311 DCHECK_EQ(this, current()); 312 if (run_loop_) { 313 pump_->Quit(); 314 } else { 315 NOTREACHED() << "Must be inside Run to call Quit"; 316 } 317 } 318 319 bool MessageLoop::IsType(Type type) const { 320 return type_ == type; 321 } 322 323 static void QuitCurrentWhenIdle() { 324 MessageLoop::current()->QuitWhenIdle(); 325 } 326 327 // static 328 Closure MessageLoop::QuitWhenIdleClosure() { 329 return Bind(&QuitCurrentWhenIdle); 330 } 331 332 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 333 if (allowed) { 334 // Kick the native pump just in case we enter a OS-driven nested message 335 // loop. 336 pump_->ScheduleWork(); 337 } 338 nestable_tasks_allowed_ = allowed; 339 } 340 341 bool MessageLoop::NestableTasksAllowed() const { 342 return nestable_tasks_allowed_; 343 } 344 345 bool MessageLoop::IsNested() { 346 return run_loop_->run_depth_ > 1; 347 } 348 349 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 350 DCHECK_EQ(this, current()); 351 task_observers_.AddObserver(task_observer); 352 } 353 354 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 355 DCHECK_EQ(this, current()); 356 task_observers_.RemoveObserver(task_observer); 357 } 358 359 bool MessageLoop::is_running() const { 360 DCHECK_EQ(this, current()); 361 return run_loop_ != NULL; 362 } 363 364 bool MessageLoop::HasHighResolutionTasks() { 365 return incoming_task_queue_->HasHighResolutionTasks(); 366 } 367 368 bool MessageLoop::IsIdleForTesting() { 369 // We only check the incoming queue, since we don't want to lock the work 370 // queue. 371 return incoming_task_queue_->IsIdleForTesting(); 372 } 373 374 //------------------------------------------------------------------------------ 375 376 // static 377 scoped_ptr<MessageLoop> MessageLoop::CreateUnbound( 378 Type type, MessagePumpFactoryCallback pump_factory) { 379 return make_scoped_ptr(new MessageLoop(type, pump_factory)); 380 } 381 382 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) 383 : type_(type), 384 #if defined(OS_WIN) 385 pending_high_res_tasks_(0), 386 in_high_res_mode_(false), 387 #endif 388 nestable_tasks_allowed_(true), 389 #if defined(OS_WIN) 390 os_modal_loop_(false), 391 #endif // OS_WIN 392 pump_factory_(pump_factory), 393 message_histogram_(NULL), 394 run_loop_(NULL), 395 incoming_task_queue_(new internal::IncomingTaskQueue(this)), 396 unbound_task_runner_( 397 new internal::MessageLoopTaskRunner(incoming_task_queue_)), 398 task_runner_(unbound_task_runner_) { 399 // If type is TYPE_CUSTOM non-null pump_factory must be given. 400 DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null()); 401 } 402 403 void MessageLoop::BindToCurrentThread() { 404 DCHECK(!pump_); 405 if (!pump_factory_.is_null()) 406 pump_ = pump_factory_.Run(); 407 else 408 pump_ = CreateMessagePumpForType(type_); 409 410 DCHECK(!current()) << "should only have one message loop per thread"; 411 lazy_tls_ptr.Pointer()->Set(this); 412 413 incoming_task_queue_->StartScheduling(); 414 unbound_task_runner_->BindToCurrentThread(); 415 unbound_task_runner_ = nullptr; 416 SetThreadTaskRunnerHandle(); 417 } 418 419 void MessageLoop::SetTaskRunner( 420 scoped_refptr<SingleThreadTaskRunner> task_runner) { 421 DCHECK_EQ(this, current()); 422 DCHECK(task_runner->BelongsToCurrentThread()); 423 DCHECK(!unbound_task_runner_); 424 task_runner_ = std::move(task_runner); 425 SetThreadTaskRunnerHandle(); 426 } 427 428 void MessageLoop::SetThreadTaskRunnerHandle() { 429 DCHECK_EQ(this, current()); 430 // Clear the previous thread task runner first, because only one can exist at 431 // a time. 432 thread_task_runner_handle_.reset(); 433 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_)); 434 } 435 436 void MessageLoop::RunHandler() { 437 DCHECK_EQ(this, current()); 438 439 StartHistogrammer(); 440 441 #if defined(OS_WIN) 442 if (run_loop_->dispatcher_ && type() == TYPE_UI) { 443 static_cast<MessagePumpForUI*>(pump_.get())-> 444 RunWithDispatcher(this, run_loop_->dispatcher_); 445 return; 446 } 447 #endif 448 449 pump_->Run(this); 450 } 451 452 bool MessageLoop::ProcessNextDelayedNonNestableTask() { 453 if (run_loop_->run_depth_ != 1) 454 return false; 455 456 if (deferred_non_nestable_work_queue_.empty()) 457 return false; 458 459 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); 460 deferred_non_nestable_work_queue_.pop(); 461 462 RunTask(pending_task); 463 return true; 464 } 465 466 void MessageLoop::RunTask(const PendingTask& pending_task) { 467 DCHECK(nestable_tasks_allowed_); 468 469 #if defined(OS_WIN) 470 if (pending_task.is_high_res) { 471 pending_high_res_tasks_--; 472 CHECK_GE(pending_high_res_tasks_, 0); 473 } 474 #endif 475 476 // Execute the task and assume the worst: It is probably not reentrant. 477 nestable_tasks_allowed_ = false; 478 479 HistogramEvent(kTaskRunEvent); 480 481 TRACE_TASK_EXECUTION("MessageLoop::RunTask", pending_task); 482 483 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 484 WillProcessTask(pending_task)); 485 task_annotator_.RunTask("MessageLoop::PostTask", pending_task); 486 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 487 DidProcessTask(pending_task)); 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 void MessageLoop::ReloadWorkQueue() { 541 // We can improve performance of our loading tasks from the incoming queue to 542 // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to 543 // load. That reduces the number of locks-per-task significantly when our 544 // queues get large. 545 if (work_queue_.empty()) { 546 #if defined(OS_WIN) 547 pending_high_res_tasks_ += 548 incoming_task_queue_->ReloadWorkQueue(&work_queue_); 549 #else 550 incoming_task_queue_->ReloadWorkQueue(&work_queue_); 551 #endif 552 } 553 } 554 555 void MessageLoop::ScheduleWork() { 556 pump_->ScheduleWork(); 557 } 558 559 //------------------------------------------------------------------------------ 560 // Method and data for histogramming events and actions taken by each instance 561 // on each thread. 562 563 void MessageLoop::StartHistogrammer() { 564 #if !defined(OS_NACL) // NaCl build has no metrics code. 565 if (enable_histogrammer_ && !message_histogram_ 566 && StatisticsRecorder::IsActive()) { 567 DCHECK(!thread_name_.empty()); 568 message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription( 569 "MsgLoop:" + thread_name_, 570 kLeastNonZeroMessageId, kMaxMessageId, 571 kNumberOfDistinctMessagesDisplayed, 572 HistogramBase::kHexRangePrintingFlag, 573 event_descriptions_); 574 } 575 #endif 576 } 577 578 void MessageLoop::HistogramEvent(int event) { 579 #if !defined(OS_NACL) 580 if (message_histogram_) 581 message_histogram_->Add(event); 582 #endif 583 } 584 585 bool MessageLoop::DoWork() { 586 if (!nestable_tasks_allowed_) { 587 // Task can't be executed right now. 588 return false; 589 } 590 591 for (;;) { 592 ReloadWorkQueue(); 593 if (work_queue_.empty()) 594 break; 595 596 // Execute oldest task. 597 do { 598 PendingTask pending_task = work_queue_.front(); 599 work_queue_.pop(); 600 if (!pending_task.delayed_run_time.is_null()) { 601 AddToDelayedWorkQueue(pending_task); 602 // If we changed the topmost task, then it is time to reschedule. 603 if (delayed_work_queue_.top().task.Equals(pending_task.task)) 604 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 605 } else { 606 if (DeferOrRunPendingTask(pending_task)) 607 return true; 608 } 609 } while (!work_queue_.empty()); 610 } 611 612 // Nothing happened. 613 return false; 614 } 615 616 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { 617 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 618 recent_time_ = *next_delayed_work_time = TimeTicks(); 619 return false; 620 } 621 622 // When we "fall behind", there will be a lot of tasks in the delayed work 623 // queue that are ready to run. To increase efficiency when we fall behind, 624 // we will only call Time::Now() intermittently, and then process all tasks 625 // that are ready to run before calling it again. As a result, the more we 626 // fall behind (and have a lot of ready-to-run delayed tasks), the more 627 // efficient we'll be at handling the tasks. 628 629 TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time; 630 if (next_run_time > recent_time_) { 631 recent_time_ = TimeTicks::Now(); // Get a better view of Now(); 632 if (next_run_time > recent_time_) { 633 *next_delayed_work_time = next_run_time; 634 return false; 635 } 636 } 637 638 PendingTask pending_task = delayed_work_queue_.top(); 639 delayed_work_queue_.pop(); 640 641 if (!delayed_work_queue_.empty()) 642 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 643 644 return DeferOrRunPendingTask(pending_task); 645 } 646 647 bool MessageLoop::DoIdleWork() { 648 if (ProcessNextDelayedNonNestableTask()) 649 return true; 650 651 if (run_loop_->quit_when_idle_received_) 652 pump_->Quit(); 653 654 // When we return we will do a kernel wait for more tasks. 655 #if defined(OS_WIN) 656 // On Windows we activate the high resolution timer so that the wait 657 // _if_ triggered by the timer happens with good resolution. If we don't 658 // do this the default resolution is 15ms which might not be acceptable 659 // for some tasks. 660 bool high_res = pending_high_res_tasks_ > 0; 661 if (high_res != in_high_res_mode_) { 662 in_high_res_mode_ = high_res; 663 Time::ActivateHighResolutionTimer(in_high_res_mode_); 664 } 665 #endif 666 return false; 667 } 668 669 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, 670 void(*deleter)(const void*), 671 const void* object) { 672 PostNonNestableTask(from_here, Bind(deleter, object)); 673 } 674 675 void MessageLoop::ReleaseSoonInternal( 676 const tracked_objects::Location& from_here, 677 void(*releaser)(const void*), 678 const void* object) { 679 PostNonNestableTask(from_here, Bind(releaser, object)); 680 } 681 682 #if !defined(OS_NACL) 683 //------------------------------------------------------------------------------ 684 // MessageLoopForUI 685 686 #if defined(OS_ANDROID) 687 void MessageLoopForUI::Start() { 688 // No Histogram support for UI message loop as it is managed by Java side 689 static_cast<MessagePumpForUI*>(pump_.get())->Start(this); 690 } 691 #endif 692 693 #if defined(OS_IOS) 694 void MessageLoopForUI::Attach() { 695 static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); 696 } 697 #endif 698 699 #if defined(USE_OZONE) || (defined(USE_X11) && !defined(USE_GLIB)) 700 bool MessageLoopForUI::WatchFileDescriptor( 701 int fd, 702 bool persistent, 703 MessagePumpLibevent::Mode mode, 704 MessagePumpLibevent::FileDescriptorWatcher *controller, 705 MessagePumpLibevent::Watcher *delegate) { 706 return static_cast<MessagePumpLibevent*>(pump_.get())->WatchFileDescriptor( 707 fd, 708 persistent, 709 mode, 710 controller, 711 delegate); 712 } 713 #endif 714 715 #endif // !defined(OS_NACL) 716 717 //------------------------------------------------------------------------------ 718 // MessageLoopForIO 719 720 MessageLoopForIO::MessageLoopForIO() : MessageLoop(TYPE_IO) {} 721 722 #if !defined(OS_NACL_SFI) 723 void MessageLoopForIO::AddIOObserver( 724 MessageLoopForIO::IOObserver* io_observer) { 725 ToPumpIO(pump_.get())->AddIOObserver(io_observer); 726 } 727 728 void MessageLoopForIO::RemoveIOObserver( 729 MessageLoopForIO::IOObserver* io_observer) { 730 ToPumpIO(pump_.get())->RemoveIOObserver(io_observer); 731 } 732 733 #if defined(OS_WIN) 734 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 735 ToPumpIO(pump_.get())->RegisterIOHandler(file, handler); 736 } 737 738 bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) { 739 return ToPumpIO(pump_.get())->RegisterJobObject(job, handler); 740 } 741 742 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 743 return ToPumpIO(pump_.get())->WaitForIOCompletion(timeout, filter); 744 } 745 #elif defined(OS_POSIX) 746 bool MessageLoopForIO::WatchFileDescriptor(int fd, 747 bool persistent, 748 Mode mode, 749 FileDescriptorWatcher* controller, 750 Watcher* delegate) { 751 return ToPumpIO(pump_.get())->WatchFileDescriptor( 752 fd, 753 persistent, 754 mode, 755 controller, 756 delegate); 757 } 758 #endif 759 760 #endif // !defined(OS_NACL_SFI) 761 762 } // namespace base 763