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
3 // found in the LICENSE file.
5 #include "base/message_loop.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_loop_proxy_impl.h"
17 #include "base/message_pump_default.h"
18 #include "base/metrics/histogram.h"
19 #include "base/metrics/statistics_recorder.h"
20 #include "base/run_loop.h"
21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/threading/thread_local.h"
24 #include "base/time.h"
25 #include "base/tracked_objects.h"
27 #if defined(OS_MACOSX)
28 #include "base/message_pump_mac.h"
30 #if defined(OS_POSIX) && !defined(OS_IOS)
31 #include "base/message_pump_libevent.h"
33 #if defined(OS_ANDROID)
34 #include "base/message_pump_android.h"
37 #if defined(TOOLKIT_GTK)
46 // A lazily created thread local storage for quick access to a thread's message
47 // loop, if one exists. This should be safe and free of static constructors.
48 LazyInstance
<base::ThreadLocalPointer
<MessageLoop
> > lazy_tls_ptr
=
49 LAZY_INSTANCE_INITIALIZER
;
51 // Logical events for Histogram profiling. Run with -message-loop-histogrammer
52 // to get an accounting of messages and actions taken on each thread.
53 const int kTaskRunEvent
= 0x1;
54 const int kTimerEvent
= 0x2;
56 // Provide range of message IDs for use in histogramming and debug display.
57 const int kLeastNonZeroMessageId
= 1;
58 const int kMaxMessageId
= 1099;
59 const int kNumberOfDistinctMessagesDisplayed
= 1100;
61 // Provide a macro that takes an expression (such as a constant, or macro
62 // constant) and creates a pair to initalize an array of pairs. In this case,
63 // our pair consists of the expressions value, and the "stringized" version
64 // of the expression (i.e., the exrpression put in quotes). For example, if
68 // then the following:
69 // VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
72 // We use the resulting array as an argument to our histogram, which reads the
73 // number as a bucket identifier, and proceeds to use the corresponding name
74 // in the pair (i.e., the quoted string) when printing out a histogram.
75 #define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
77 const LinearHistogram::DescriptionPair event_descriptions_
[] = {
78 // Provide some pretty print capability in our histogram for our internal
81 // A few events we handle (kindred to messages), and used to profile actions.
82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent
)
83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent
)
85 {-1, NULL
} // The list must be null terminated, per API to histogram.
88 bool enable_histogrammer_
= false;
90 MessageLoop::MessagePumpFactory
* message_pump_for_ui_factory_
= NULL
;
92 // Create a process-wide unique ID to represent this task in trace events. This
93 // will be mangled with a Process ID hash to reduce the likelyhood of colliding
94 // with MessageLoop pointers on other processes.
95 uint64
GetTaskTraceID(const PendingTask
& task
, MessageLoop
* loop
) {
96 return (static_cast<uint64
>(task
.sequence_num
) << 32) |
97 static_cast<uint64
>(reinterpret_cast<intptr_t>(loop
));
102 //------------------------------------------------------------------------------
106 // Upon a SEH exception in this thread, it restores the original unhandled
108 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter
) {
109 ::SetUnhandledExceptionFilter(old_filter
);
110 return EXCEPTION_CONTINUE_SEARCH
;
113 // Retrieves a pointer to the current unhandled exception filter. There
114 // is no standalone getter method.
115 static LPTOP_LEVEL_EXCEPTION_FILTER
GetTopSEHFilter() {
116 LPTOP_LEVEL_EXCEPTION_FILTER top_filter
= NULL
;
117 top_filter
= ::SetUnhandledExceptionFilter(0);
118 ::SetUnhandledExceptionFilter(top_filter
);
122 #endif // defined(OS_WIN)
124 //------------------------------------------------------------------------------
126 MessageLoop::TaskObserver::TaskObserver() {
129 MessageLoop::TaskObserver::~TaskObserver() {
132 MessageLoop::DestructionObserver::~DestructionObserver() {
135 //------------------------------------------------------------------------------
137 MessageLoop::MessageLoop(Type type
)
139 nestable_tasks_allowed_(true),
140 exception_restoration_(false),
141 message_histogram_(NULL
),
144 os_modal_loop_(false),
146 next_sequence_num_(0) {
147 DCHECK(!current()) << "should only have one message loop per thread";
148 lazy_tls_ptr
.Pointer()->Set(this);
150 message_loop_proxy_
= new MessageLoopProxyImpl();
151 thread_task_runner_handle_
.reset(
152 new ThreadTaskRunnerHandle(message_loop_proxy_
));
154 // TODO(rvargas): Get rid of the OS guards.
156 #define MESSAGE_PUMP_UI new MessagePumpForUI()
157 #define MESSAGE_PUMP_IO new MessagePumpForIO()
158 #elif defined(OS_IOS)
159 #define MESSAGE_PUMP_UI MessagePumpMac::Create()
160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO()
161 #elif defined(OS_MACOSX)
162 #define MESSAGE_PUMP_UI MessagePumpMac::Create()
163 #define MESSAGE_PUMP_IO new MessagePumpLibevent()
164 #elif defined(OS_NACL)
165 // Currently NaCl doesn't have a UI MessageLoop.
166 // TODO(abarth): Figure out if we need this.
167 #define MESSAGE_PUMP_UI NULL
168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and
169 // doesn't require extra support for watching file descriptors.
170 #define MESSAGE_PUMP_IO new MessagePumpDefault();
171 #elif defined(OS_POSIX) // POSIX but not MACOSX.
172 #define MESSAGE_PUMP_UI new MessagePumpForUI()
173 #define MESSAGE_PUMP_IO new MessagePumpLibevent()
175 #error Not implemented
178 if (type_
== TYPE_UI
) {
179 if (message_pump_for_ui_factory_
)
180 pump_
= message_pump_for_ui_factory_();
182 pump_
= MESSAGE_PUMP_UI
;
183 } else if (type_
== TYPE_IO
) {
184 pump_
= MESSAGE_PUMP_IO
;
186 DCHECK_EQ(TYPE_DEFAULT
, type_
);
187 pump_
= new MessagePumpDefault();
191 MessageLoop::~MessageLoop() {
192 DCHECK_EQ(this, current());
196 // Clean up any unprocessed tasks, but take care: deleting a task could
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
198 // limit on the number of times we will allow a deleted task to generate more
199 // tasks. Normally, we should only pass through this loop once or twice. If
200 // we end up hitting the loop limit, then it is probably due to one task that
201 // is being stubborn. Inspect the queues to see who is left.
203 for (int i
= 0; i
< 100; ++i
) {
204 DeletePendingTasks();
206 // If we end up with empty queues, then break out of the loop.
207 did_work
= DeletePendingTasks();
213 // Let interested parties have one last shot at accessing this.
214 FOR_EACH_OBSERVER(DestructionObserver
, destruction_observers_
,
215 WillDestroyCurrentMessageLoop());
217 thread_task_runner_handle_
.reset();
219 // Tell the message_loop_proxy that we are dying.
220 static_cast<MessageLoopProxyImpl
*>(message_loop_proxy_
.get())->
221 WillDestroyCurrentMessageLoop();
222 message_loop_proxy_
= NULL
;
224 // OK, now make it so that no one can find us.
225 lazy_tls_ptr
.Pointer()->Set(NULL
);
228 // If we left the high-resolution timer activated, deactivate it now.
229 // Doing this is not-critical, it is mainly to make sure we track
230 // the high resolution timer activations properly in our unit tests.
231 if (!high_resolution_timer_expiration_
.is_null()) {
232 Time::ActivateHighResolutionTimer(false);
233 high_resolution_timer_expiration_
= TimeTicks();
239 MessageLoop
* MessageLoop::current() {
240 // TODO(darin): sadly, we cannot enable this yet since people call us even
241 // when they have no intention of using us.
242 // DCHECK(loop) << "Ouch, did you forget to initialize me?";
243 return lazy_tls_ptr
.Pointer()->Get();
247 void MessageLoop::EnableHistogrammer(bool enable
) {
248 enable_histogrammer_
= enable
;
252 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory
* factory
) {
253 if (message_pump_for_ui_factory_
)
256 message_pump_for_ui_factory_
= factory
;
260 void MessageLoop::AddDestructionObserver(
261 DestructionObserver
* destruction_observer
) {
262 DCHECK_EQ(this, current());
263 destruction_observers_
.AddObserver(destruction_observer
);
266 void MessageLoop::RemoveDestructionObserver(
267 DestructionObserver
* destruction_observer
) {
268 DCHECK_EQ(this, current());
269 destruction_observers_
.RemoveObserver(destruction_observer
);
272 void MessageLoop::PostTask(
273 const tracked_objects::Location
& from_here
,
274 const Closure
& task
) {
275 DCHECK(!task
.is_null()) << from_here
.ToString();
276 PendingTask
pending_task(
277 from_here
, task
, CalculateDelayedRuntime(TimeDelta()), true);
278 AddToIncomingQueue(&pending_task
, false);
281 bool MessageLoop::TryPostTask(
282 const tracked_objects::Location
& from_here
,
283 const Closure
& task
) {
284 DCHECK(!task
.is_null()) << from_here
.ToString();
285 PendingTask
pending_task(
286 from_here
, task
, CalculateDelayedRuntime(TimeDelta()), true);
287 return AddToIncomingQueue(&pending_task
, true);
290 void MessageLoop::PostDelayedTask(
291 const tracked_objects::Location
& from_here
,
294 DCHECK(!task
.is_null()) << from_here
.ToString();
295 PendingTask
pending_task(
296 from_here
, task
, CalculateDelayedRuntime(delay
), true);
297 AddToIncomingQueue(&pending_task
, false);
300 void MessageLoop::PostNonNestableTask(
301 const tracked_objects::Location
& from_here
,
302 const Closure
& task
) {
303 DCHECK(!task
.is_null()) << from_here
.ToString();
304 PendingTask
pending_task(
305 from_here
, task
, CalculateDelayedRuntime(TimeDelta()), false);
306 AddToIncomingQueue(&pending_task
, false);
309 void MessageLoop::PostNonNestableDelayedTask(
310 const tracked_objects::Location
& from_here
,
313 DCHECK(!task
.is_null()) << from_here
.ToString();
314 PendingTask
pending_task(
315 from_here
, task
, CalculateDelayedRuntime(delay
), false);
316 AddToIncomingQueue(&pending_task
, false);
319 void MessageLoop::Run() {
324 void MessageLoop::RunUntilIdle() {
326 run_loop
.RunUntilIdle();
329 void MessageLoop::QuitWhenIdle() {
330 DCHECK_EQ(this, current());
332 run_loop_
->quit_when_idle_received_
= true;
334 NOTREACHED() << "Must be inside Run to call Quit";
338 void MessageLoop::QuitNow() {
339 DCHECK_EQ(this, current());
343 NOTREACHED() << "Must be inside Run to call Quit";
347 bool MessageLoop::IsType(Type type
) const {
348 return type_
== type
;
351 static void QuitCurrentWhenIdle() {
352 MessageLoop::current()->QuitWhenIdle();
356 Closure
MessageLoop::QuitWhenIdleClosure() {
357 return Bind(&QuitCurrentWhenIdle
);
360 void MessageLoop::SetNestableTasksAllowed(bool allowed
) {
361 if (nestable_tasks_allowed_
!= allowed
) {
362 nestable_tasks_allowed_
= allowed
;
363 if (!nestable_tasks_allowed_
)
365 // Start the native pump if we are not already pumping.
366 pump_
->ScheduleWork();
370 bool MessageLoop::NestableTasksAllowed() const {
371 return nestable_tasks_allowed_
;
374 bool MessageLoop::IsNested() {
375 return run_loop_
->run_depth_
> 1;
378 void MessageLoop::AddTaskObserver(TaskObserver
* task_observer
) {
379 DCHECK_EQ(this, current());
380 task_observers_
.AddObserver(task_observer
);
383 void MessageLoop::RemoveTaskObserver(TaskObserver
* task_observer
) {
384 DCHECK_EQ(this, current());
385 task_observers_
.RemoveObserver(task_observer
);
388 void MessageLoop::AssertIdle() const {
389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
390 AutoLock
lock(incoming_queue_lock_
);
391 DCHECK(incoming_queue_
.empty());
394 bool MessageLoop::is_running() const {
395 DCHECK_EQ(this, current());
396 return run_loop_
!= NULL
;
399 //------------------------------------------------------------------------------
401 // Runs the loop in two different SEH modes:
402 // enable_SEH_restoration_ = false : any unhandled exception goes to the last
403 // one that calls SetUnhandledExceptionFilter().
404 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter
405 // that was existed before the loop was run.
406 void MessageLoop::RunHandler() {
408 if (exception_restoration_
) {
409 RunInternalInSEHFrame();
418 __declspec(noinline
) void MessageLoop::RunInternalInSEHFrame() {
419 LPTOP_LEVEL_EXCEPTION_FILTER current_filter
= GetTopSEHFilter();
422 } __except(SEHFilter(current_filter
)) {
428 void MessageLoop::RunInternal() {
429 DCHECK_EQ(this, current());
433 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
434 if (run_loop_
->dispatcher_
&& type() == TYPE_UI
) {
435 static_cast<MessagePumpForUI
*>(pump_
.get())->
436 RunWithDispatcher(this, run_loop_
->dispatcher_
);
444 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
445 if (run_loop_
->run_depth_
!= 1)
448 if (deferred_non_nestable_work_queue_
.empty())
451 PendingTask pending_task
= deferred_non_nestable_work_queue_
.front();
452 deferred_non_nestable_work_queue_
.pop();
454 RunTask(pending_task
);
458 void MessageLoop::RunTask(const PendingTask
& pending_task
) {
459 TRACE_EVENT_FLOW_END0("task", "MessageLoop::PostTask",
460 TRACE_ID_MANGLE(GetTaskTraceID(pending_task
, this)));
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 DCHECK(nestable_tasks_allowed_
);
465 // Execute the task and assume the worst: It is probably not reentrant.
466 nestable_tasks_allowed_
= false;
468 // Before running the task, store the program counter where it was posted
469 // and deliberately alias it to ensure it is on the stack if the task
470 // crashes. Be careful not to assume that the variable itself will have the
471 // expected value when displayed by the optimizer in an optimized build.
472 // Look at a memory dump of the stack.
473 const void* program_counter
=
474 pending_task
.posted_from
.program_counter();
475 debug::Alias(&program_counter
);
477 HistogramEvent(kTaskRunEvent
);
479 tracked_objects::TrackedTime start_time
=
480 tracked_objects::ThreadData::NowForStartOfRun(pending_task
.birth_tally
);
482 FOR_EACH_OBSERVER(TaskObserver
, task_observers_
,
483 WillProcessTask(pending_task
));
484 pending_task
.task
.Run();
485 FOR_EACH_OBSERVER(TaskObserver
, task_observers_
,
486 DidProcessTask(pending_task
));
488 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task
,
489 start_time
, tracked_objects::ThreadData::NowForEndOfRun());
491 nestable_tasks_allowed_
= true;
494 bool MessageLoop::DeferOrRunPendingTask(const PendingTask
& pending_task
) {
495 if (pending_task
.nestable
|| run_loop_
->run_depth_
== 1) {
496 RunTask(pending_task
);
497 // Show that we ran a task (Note: a new one might arrive as a
502 // We couldn't run the task now because we're in a nested message loop
503 // and the task isn't nestable.
504 deferred_non_nestable_work_queue_
.push(pending_task
);
508 void MessageLoop::AddToDelayedWorkQueue(const PendingTask
& pending_task
) {
509 // Move to the delayed work queue.
510 delayed_work_queue_
.push(pending_task
);
513 void MessageLoop::ReloadWorkQueue() {
514 // We can improve performance of our loading tasks from incoming_queue_ to
515 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
516 // load. That reduces the number of locks-per-task significantly when our
518 if (!work_queue_
.empty())
519 return; // Wait till we *really* need to lock and load.
521 // Acquire all we can from the inter-thread queue with one lock acquisition.
523 AutoLock
lock(incoming_queue_lock_
);
524 if (incoming_queue_
.empty())
526 incoming_queue_
.Swap(&work_queue_
); // Constant time
527 DCHECK(incoming_queue_
.empty());
531 bool MessageLoop::DeletePendingTasks() {
532 bool did_work
= !work_queue_
.empty();
533 while (!work_queue_
.empty()) {
534 PendingTask pending_task
= work_queue_
.front();
536 if (!pending_task
.delayed_run_time
.is_null()) {
537 // We want to delete delayed tasks in the same order in which they would
538 // normally be deleted in case of any funny dependencies between delayed
540 AddToDelayedWorkQueue(pending_task
);
543 did_work
|= !deferred_non_nestable_work_queue_
.empty();
544 while (!deferred_non_nestable_work_queue_
.empty()) {
545 deferred_non_nestable_work_queue_
.pop();
547 did_work
|= !delayed_work_queue_
.empty();
549 // Historically, we always delete the task regardless of valgrind status. It's
550 // not completely clear why we want to leak them in the loops above. This
551 // code is replicating legacy behavior, and should not be considered
552 // absolutely "correct" behavior. See TODO above about deleting all tasks
554 while (!delayed_work_queue_
.empty()) {
555 delayed_work_queue_
.pop();
560 TimeTicks
MessageLoop::CalculateDelayedRuntime(TimeDelta delay
) {
561 TimeTicks delayed_run_time
;
562 if (delay
> TimeDelta()) {
563 delayed_run_time
= TimeTicks::Now() + delay
;
566 if (high_resolution_timer_expiration_
.is_null()) {
567 // Windows timers are granular to 15.6ms. If we only set high-res
568 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
569 // which as a percentage is pretty inaccurate. So enable high
570 // res timers for any timer which is within 2x of the granularity.
571 // This is a tradeoff between accuracy and power management.
572 bool needs_high_res_timers
= delay
.InMilliseconds() <
573 (2 * Time::kMinLowResolutionThresholdMs
);
574 if (needs_high_res_timers
) {
575 if (Time::ActivateHighResolutionTimer(true)) {
576 high_resolution_timer_expiration_
= TimeTicks::Now() +
577 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs
);
583 DCHECK_EQ(delay
.InMilliseconds(), 0) << "delay should not be negative";
587 if (!high_resolution_timer_expiration_
.is_null()) {
588 if (TimeTicks::Now() > high_resolution_timer_expiration_
) {
589 Time::ActivateHighResolutionTimer(false);
590 high_resolution_timer_expiration_
= TimeTicks();
595 return delayed_run_time
;
598 // Possibly called on a background thread!
599 bool MessageLoop::AddToIncomingQueue(PendingTask
* pending_task
,
601 // Warning: Don't try to short-circuit, and handle this thread's tasks more
602 // directly, as it could starve handling of foreign threads. Put every task
605 scoped_refptr
<MessagePump
> pump
;
608 if (!incoming_queue_lock_
.Try()) {
609 pending_task
->task
.Reset();
613 incoming_queue_lock_
.Acquire();
615 AutoLock
locked(incoming_queue_lock_
, AutoLock::AlreadyAcquired());
616 // Initialize the sequence number. The sequence number is used for delayed
617 // tasks (to faciliate FIFO sorting when two tasks have the same
618 // delayed_run_time value) and for identifying the task in about:tracing.
619 pending_task
->sequence_num
= next_sequence_num_
++;
621 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask",
622 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task
, this)));
624 bool was_empty
= incoming_queue_
.empty();
625 incoming_queue_
.push(*pending_task
);
626 pending_task
->task
.Reset();
628 return true; // Someone else should have started the sub-pump.
632 // Since the incoming_queue_ may contain a task that destroys this message
633 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
634 // We use a stack-based reference to the message pump so that we can call
635 // ScheduleWork outside of incoming_queue_lock_.
637 pump
->ScheduleWork();
641 //------------------------------------------------------------------------------
642 // Method and data for histogramming events and actions taken by each instance
645 void MessageLoop::StartHistogrammer() {
646 #if !defined(OS_NACL) // NaCl build has no metrics code.
647 if (enable_histogrammer_
&& !message_histogram_
648 && StatisticsRecorder::IsActive()) {
649 DCHECK(!thread_name_
.empty());
650 message_histogram_
= LinearHistogram::FactoryGetWithRangeDescription(
651 "MsgLoop:" + thread_name_
,
652 kLeastNonZeroMessageId
, kMaxMessageId
,
653 kNumberOfDistinctMessagesDisplayed
,
654 message_histogram_
->kHexRangePrintingFlag
,
655 event_descriptions_
);
660 void MessageLoop::HistogramEvent(int event
) {
661 #if !defined(OS_NACL)
662 if (message_histogram_
)
663 message_histogram_
->Add(event
);
667 bool MessageLoop::DoWork() {
668 if (!nestable_tasks_allowed_
) {
669 // Task can't be executed right now.
675 if (work_queue_
.empty())
678 // Execute oldest task.
680 PendingTask pending_task
= work_queue_
.front();
682 if (!pending_task
.delayed_run_time
.is_null()) {
683 AddToDelayedWorkQueue(pending_task
);
684 // If we changed the topmost task, then it is time to reschedule.
685 if (delayed_work_queue_
.top().task
.Equals(pending_task
.task
))
686 pump_
->ScheduleDelayedWork(pending_task
.delayed_run_time
);
688 if (DeferOrRunPendingTask(pending_task
))
691 } while (!work_queue_
.empty());
698 bool MessageLoop::DoDelayedWork(TimeTicks
* next_delayed_work_time
) {
699 if (!nestable_tasks_allowed_
|| delayed_work_queue_
.empty()) {
700 recent_time_
= *next_delayed_work_time
= TimeTicks();
704 // When we "fall behind," there will be a lot of tasks in the delayed work
705 // queue that are ready to run. To increase efficiency when we fall behind,
706 // we will only call Time::Now() intermittently, and then process all tasks
707 // that are ready to run before calling it again. As a result, the more we
708 // fall behind (and have a lot of ready-to-run delayed tasks), the more
709 // efficient we'll be at handling the tasks.
711 TimeTicks next_run_time
= delayed_work_queue_
.top().delayed_run_time
;
712 if (next_run_time
> recent_time_
) {
713 recent_time_
= TimeTicks::Now(); // Get a better view of Now();
714 if (next_run_time
> recent_time_
) {
715 *next_delayed_work_time
= next_run_time
;
720 PendingTask pending_task
= delayed_work_queue_
.top();
721 delayed_work_queue_
.pop();
723 if (!delayed_work_queue_
.empty())
724 *next_delayed_work_time
= delayed_work_queue_
.top().delayed_run_time
;
726 return DeferOrRunPendingTask(pending_task
);
729 bool MessageLoop::DoIdleWork() {
730 if (ProcessNextDelayedNonNestableTask())
733 if (run_loop_
->quit_when_idle_received_
)
739 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location
& from_here
,
740 void(*deleter
)(const void*),
741 const void* object
) {
742 PostNonNestableTask(from_here
, Bind(deleter
, object
));
745 void MessageLoop::ReleaseSoonInternal(
746 const tracked_objects::Location
& from_here
,
747 void(*releaser
)(const void*),
748 const void* object
) {
749 PostNonNestableTask(from_here
, Bind(releaser
, object
));
752 //------------------------------------------------------------------------------
756 void MessageLoopForUI::DidProcessMessage(const MSG
& message
) {
757 pump_win()->DidProcessMessage(message
);
759 #endif // defined(OS_WIN)
761 #if defined(OS_ANDROID)
762 void MessageLoopForUI::Start() {
763 // No Histogram support for UI message loop as it is managed by Java side
764 static_cast<MessagePumpForUI
*>(pump_
.get())->Start(this);
769 void MessageLoopForUI::Attach() {
770 static_cast<MessagePumpUIApplication
*>(pump_
.get())->Attach(this);
774 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
775 void MessageLoopForUI::AddObserver(Observer
* observer
) {
776 pump_ui()->AddObserver(observer
);
779 void MessageLoopForUI::RemoveObserver(Observer
* observer
) {
780 pump_ui()->RemoveObserver(observer
);
783 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
785 //------------------------------------------------------------------------------
790 void MessageLoopForIO::RegisterIOHandler(HANDLE file
, IOHandler
* handler
) {
791 pump_io()->RegisterIOHandler(file
, handler
);
794 bool MessageLoopForIO::RegisterJobObject(HANDLE job
, IOHandler
* handler
) {
795 return pump_io()->RegisterJobObject(job
, handler
);
798 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout
, IOHandler
* filter
) {
799 return pump_io()->WaitForIOCompletion(timeout
, filter
);
802 #elif defined(OS_IOS)
804 bool MessageLoopForIO::WatchFileDescriptor(int fd
,
807 FileDescriptorWatcher
*controller
,
809 return pump_io()->WatchFileDescriptor(
817 #elif defined(OS_POSIX) && !defined(OS_NACL)
819 bool MessageLoopForIO::WatchFileDescriptor(int fd
,
822 FileDescriptorWatcher
*controller
,
824 return pump_libevent()->WatchFileDescriptor(