1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6
7 #include "base/message_loop.h"
8
9 #include <algorithm>
10
11 #include "mozilla/Atomics.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/message_pump_default.h"
15 #include "base/string_util.h"
16 #include "base/thread_local.h"
17
18 #if defined(OS_MACOSX)
19 # include "base/message_pump_mac.h"
20 #endif
21 #if defined(OS_POSIX)
22 # include "base/message_pump_libevent.h"
23 #endif
24 #if defined(OS_LINUX) || defined(OS_BSD)
25 # if defined(MOZ_WIDGET_GTK)
26 # include "base/message_pump_glib.h"
27 # endif
28 #endif
29 #ifdef ANDROID
30 # include "base/message_pump_android.h"
31 #endif
32 #include "nsISerialEventTarget.h"
33 #ifdef MOZ_TASK_TRACER
34 # include "GeckoTaskTracer.h"
35 # include "TracedTaskCommon.h"
36 #endif
37
38 #include "MessagePump.h"
39
40 using base::Time;
41 using base::TimeDelta;
42 using base::TimeTicks;
43
44 using mozilla::Runnable;
45
get_tls_ptr()46 static base::ThreadLocalPointer<MessageLoop>& get_tls_ptr() {
47 static base::ThreadLocalPointer<MessageLoop> tls_ptr;
48 return tls_ptr;
49 }
50
51 //------------------------------------------------------------------------------
52
53 // Logical events for Histogram profiling. Run with -message-loop-histogrammer
54 // to get an accounting of messages and actions taken on each thread.
55 static const int kTaskRunEvent = 0x1;
56 static const int kTimerEvent = 0x2;
57
58 // Provide range of message IDs for use in histogramming and debug display.
59 static const int kLeastNonZeroMessageId = 1;
60 static const int kMaxMessageId = 1099;
61 static const int kNumberOfDistinctMessagesDisplayed = 1100;
62
63 //------------------------------------------------------------------------------
64
65 #if defined(OS_WIN)
66
67 // Upon a SEH exception in this thread, it restores the original unhandled
68 // exception filter.
SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter)69 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
70 ::SetUnhandledExceptionFilter(old_filter);
71 return EXCEPTION_CONTINUE_SEARCH;
72 }
73
74 // Retrieves a pointer to the current unhandled exception filter. There
75 // is no standalone getter method.
GetTopSEHFilter()76 static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
77 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
78 top_filter = ::SetUnhandledExceptionFilter(0);
79 ::SetUnhandledExceptionFilter(top_filter);
80 return top_filter;
81 }
82
83 #endif // defined(OS_WIN)
84
85 //------------------------------------------------------------------------------
86
87 class MessageLoop::EventTarget : public nsISerialEventTarget,
88 public MessageLoop::DestructionObserver {
89 public:
90 NS_DECL_THREADSAFE_ISUPPORTS
91 NS_DECL_NSIEVENTTARGET_FULL
92
EventTarget(MessageLoop * aLoop)93 explicit EventTarget(MessageLoop* aLoop) : mLoop(aLoop) {
94 aLoop->AddDestructionObserver(this);
95 }
96
97 private:
~EventTarget()98 virtual ~EventTarget() {
99 if (mLoop) {
100 mLoop->RemoveDestructionObserver(this);
101 }
102 }
103
WillDestroyCurrentMessageLoop()104 void WillDestroyCurrentMessageLoop() override {
105 mLoop->RemoveDestructionObserver(this);
106 mLoop = nullptr;
107 }
108
109 MessageLoop* mLoop;
110 };
111
NS_IMPL_ISUPPORTS(MessageLoop::EventTarget,nsIEventTarget,nsISerialEventTarget)112 NS_IMPL_ISUPPORTS(MessageLoop::EventTarget, nsIEventTarget,
113 nsISerialEventTarget)
114
115 NS_IMETHODIMP_(bool)
116 MessageLoop::EventTarget::IsOnCurrentThreadInfallible() {
117 return mLoop == MessageLoop::current();
118 }
119
120 NS_IMETHODIMP
IsOnCurrentThread(bool * aResult)121 MessageLoop::EventTarget::IsOnCurrentThread(bool* aResult) {
122 *aResult = IsOnCurrentThreadInfallible();
123 return NS_OK;
124 }
125
126 NS_IMETHODIMP
DispatchFromScript(nsIRunnable * aEvent,uint32_t aFlags)127 MessageLoop::EventTarget::DispatchFromScript(nsIRunnable* aEvent,
128 uint32_t aFlags) {
129 nsCOMPtr<nsIRunnable> event(aEvent);
130 return Dispatch(event.forget(), aFlags);
131 }
132
133 NS_IMETHODIMP
Dispatch(already_AddRefed<nsIRunnable> aEvent,uint32_t aFlags)134 MessageLoop::EventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
135 uint32_t aFlags) {
136 if (!mLoop) {
137 return NS_ERROR_NOT_INITIALIZED;
138 }
139
140 if (aFlags != NS_DISPATCH_NORMAL) {
141 return NS_ERROR_NOT_IMPLEMENTED;
142 }
143
144 mLoop->PostTask(std::move(aEvent));
145 return NS_OK;
146 }
147
148 NS_IMETHODIMP
DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,uint32_t aDelayMs)149 MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
150 uint32_t aDelayMs) {
151 if (!mLoop) {
152 return NS_ERROR_NOT_INITIALIZED;
153 }
154
155 mLoop->PostDelayedTask(std::move(aEvent), aDelayMs);
156 return NS_OK;
157 }
158
159 //------------------------------------------------------------------------------
160
161 // static
current()162 MessageLoop* MessageLoop::current() { return get_tls_ptr().Get(); }
163
164 // static
set_current(MessageLoop * loop)165 void MessageLoop::set_current(MessageLoop* loop) { get_tls_ptr().Set(loop); }
166
167 static mozilla::Atomic<int32_t> message_loop_id_seq(0);
168
MessageLoop(Type type,nsIEventTarget * aEventTarget)169 MessageLoop::MessageLoop(Type type, nsIEventTarget* aEventTarget)
170 : type_(type),
171 id_(++message_loop_id_seq),
172 nestable_tasks_allowed_(true),
173 exception_restoration_(false),
174 incoming_queue_lock_("MessageLoop Incoming Queue Lock"),
175 state_(NULL),
176 run_depth_base_(1),
177 shutting_down_(false),
178 #ifdef OS_WIN
179 os_modal_loop_(false),
180 #endif // OS_WIN
181 transient_hang_timeout_(0),
182 permanent_hang_timeout_(0),
183 next_sequence_num_(0) {
184 DCHECK(!current()) << "should only have one message loop per thread";
185 get_tls_ptr().Set(this);
186
187 // Must initialize after current() is initialized.
188 mEventTarget = new EventTarget(this);
189
190 switch (type_) {
191 case TYPE_MOZILLA_PARENT:
192 MOZ_RELEASE_ASSERT(!aEventTarget);
193 pump_ = new mozilla::ipc::MessagePump(aEventTarget);
194 return;
195 case TYPE_MOZILLA_CHILD:
196 MOZ_RELEASE_ASSERT(!aEventTarget);
197 pump_ = new mozilla::ipc::MessagePumpForChildProcess();
198 // There is a MessageLoop Run call from XRE_InitChildProcess
199 // and another one from MessagePumpForChildProcess. The one
200 // from MessagePumpForChildProcess becomes the base, so we need
201 // to set run_depth_base_ to 2 or we'll never be able to process
202 // Idle tasks.
203 run_depth_base_ = 2;
204 return;
205 case TYPE_MOZILLA_NONMAINTHREAD:
206 pump_ = new mozilla::ipc::MessagePumpForNonMainThreads(aEventTarget);
207 return;
208 #if defined(OS_WIN)
209 case TYPE_MOZILLA_NONMAINUITHREAD:
210 pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aEventTarget);
211 return;
212 #endif
213 #if defined(MOZ_WIDGET_ANDROID)
214 case TYPE_MOZILLA_ANDROID_UI:
215 MOZ_RELEASE_ASSERT(aEventTarget);
216 pump_ = new mozilla::ipc::MessagePumpForAndroidUI(aEventTarget);
217 return;
218 #endif // defined(MOZ_WIDGET_ANDROID)
219 default:
220 // Create one of Chromium's standard MessageLoop types below.
221 break;
222 }
223
224 #if defined(OS_WIN)
225 // TODO(rvargas): Get rid of the OS guards.
226 if (type_ == TYPE_DEFAULT) {
227 pump_ = new base::MessagePumpDefault();
228 } else if (type_ == TYPE_IO) {
229 pump_ = new base::MessagePumpForIO();
230 } else {
231 DCHECK(type_ == TYPE_UI);
232 pump_ = new base::MessagePumpForUI();
233 }
234 #elif defined(OS_POSIX)
235 if (type_ == TYPE_UI) {
236 # if defined(OS_MACOSX)
237 pump_ = base::MessagePumpMac::Create();
238 # elif defined(OS_LINUX) || defined(OS_BSD)
239 pump_ = new base::MessagePumpForUI();
240 # endif // OS_LINUX
241 } else if (type_ == TYPE_IO) {
242 pump_ = new base::MessagePumpLibevent();
243 } else {
244 pump_ = new base::MessagePumpDefault();
245 }
246 #endif // OS_POSIX
247 }
248
~MessageLoop()249 MessageLoop::~MessageLoop() {
250 DCHECK(this == current());
251
252 // Let interested parties have one last shot at accessing this.
253 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
254 WillDestroyCurrentMessageLoop());
255
256 DCHECK(!state_);
257
258 // Clean up any unprocessed tasks, but take care: deleting a task could
259 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
260 // limit on the number of times we will allow a deleted task to generate more
261 // tasks. Normally, we should only pass through this loop once or twice. If
262 // we end up hitting the loop limit, then it is probably due to one task that
263 // is being stubborn. Inspect the queues to see who is left.
264 bool did_work;
265 for (int i = 0; i < 100; ++i) {
266 DeletePendingTasks();
267 ReloadWorkQueue();
268 // If we end up with empty queues, then break out of the loop.
269 did_work = DeletePendingTasks();
270 if (!did_work) break;
271 }
272 DCHECK(!did_work);
273
274 // OK, now make it so that no one can find us.
275 get_tls_ptr().Set(NULL);
276 }
277
AddDestructionObserver(DestructionObserver * obs)278 void MessageLoop::AddDestructionObserver(DestructionObserver* obs) {
279 DCHECK(this == current());
280 destruction_observers_.AddObserver(obs);
281 }
282
RemoveDestructionObserver(DestructionObserver * obs)283 void MessageLoop::RemoveDestructionObserver(DestructionObserver* obs) {
284 DCHECK(this == current());
285 destruction_observers_.RemoveObserver(obs);
286 }
287
Run()288 void MessageLoop::Run() {
289 AutoRunState save_state(this);
290 RunHandler();
291 }
292
293 // Runs the loop in two different SEH modes:
294 // enable_SEH_restoration_ = false : any unhandled exception goes to the last
295 // one that calls SetUnhandledExceptionFilter().
296 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter
297 // that was existed before the loop was run.
RunHandler()298 void MessageLoop::RunHandler() {
299 #if defined(OS_WIN)
300 if (exception_restoration_) {
301 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
302 MOZ_SEH_TRY { RunInternal(); }
303 MOZ_SEH_EXCEPT(SEHFilter(current_filter)) {}
304 return;
305 }
306 #endif
307
308 RunInternal();
309 }
310
311 //------------------------------------------------------------------------------
312
RunInternal()313 void MessageLoop::RunInternal() {
314 DCHECK(this == current());
315 pump_->Run(this);
316 }
317
318 //------------------------------------------------------------------------------
319 // Wrapper functions for use in above message loop framework.
320
ProcessNextDelayedNonNestableTask()321 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
322 if (state_->run_depth > run_depth_base_) return false;
323
324 if (deferred_non_nestable_work_queue_.empty()) return false;
325
326 nsCOMPtr<nsIRunnable> task =
327 std::move(deferred_non_nestable_work_queue_.front().task);
328 deferred_non_nestable_work_queue_.pop();
329
330 RunTask(task.forget());
331 return true;
332 }
333
334 //------------------------------------------------------------------------------
335
Quit()336 void MessageLoop::Quit() {
337 DCHECK(current() == this);
338 if (state_) {
339 state_->quit_received = true;
340 } else {
341 NOTREACHED() << "Must be inside Run to call Quit";
342 }
343 }
344
PostTask(already_AddRefed<nsIRunnable> task)345 void MessageLoop::PostTask(already_AddRefed<nsIRunnable> task) {
346 PostTask_Helper(std::move(task), 0);
347 }
348
PostDelayedTask(already_AddRefed<nsIRunnable> task,int delay_ms)349 void MessageLoop::PostDelayedTask(already_AddRefed<nsIRunnable> task,
350 int delay_ms) {
351 PostTask_Helper(std::move(task), delay_ms);
352 }
353
PostIdleTask(already_AddRefed<nsIRunnable> task)354 void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
355 DCHECK(current() == this);
356 MOZ_ASSERT(NS_IsMainThread());
357
358 PendingTask pending_task(std::move(task), false);
359 deferred_non_nestable_work_queue_.push(std::move(pending_task));
360 }
361
362 // Possibly called on a background thread!
PostTask_Helper(already_AddRefed<nsIRunnable> task,int delay_ms)363 void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task,
364 int delay_ms) {
365 if (nsIEventTarget* target = pump_->GetXPCOMThread()) {
366 nsresult rv;
367 if (delay_ms) {
368 rv = target->DelayedDispatch(std::move(task), delay_ms);
369 } else {
370 rv = target->Dispatch(std::move(task), 0);
371 }
372 MOZ_ALWAYS_SUCCEEDS(rv);
373 return;
374 }
375
376 // Tasks should only be queued before or during the Run loop, not after.
377 MOZ_ASSERT(!shutting_down_);
378
379 #ifdef MOZ_TASK_TRACER
380 nsCOMPtr<nsIRunnable> tracedTask = task;
381 if (mozilla::tasktracer::IsStartLogging()) {
382 tracedTask = mozilla::tasktracer::CreateTracedRunnable(tracedTask.forget());
383 (static_cast<mozilla::tasktracer::TracedRunnable*>(tracedTask.get()))
384 ->DispatchTask();
385 }
386 PendingTask pending_task(tracedTask.forget(), true);
387 #else
388 PendingTask pending_task(std::move(task), true);
389 #endif
390
391 if (delay_ms > 0) {
392 pending_task.delayed_run_time =
393 TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
394 } else {
395 DCHECK(delay_ms == 0) << "delay should not be negative";
396 }
397
398 // Warning: Don't try to short-circuit, and handle this thread's tasks more
399 // directly, as it could starve handling of foreign threads. Put every task
400 // into this queue.
401
402 RefPtr<base::MessagePump> pump;
403 {
404 mozilla::MutexAutoLock locked(incoming_queue_lock_);
405 incoming_queue_.push(std::move(pending_task));
406 pump = pump_;
407 }
408 // Since the incoming_queue_ may contain a task that destroys this message
409 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
410 // We use a stack-based reference to the message pump so that we can call
411 // ScheduleWork outside of incoming_queue_lock_.
412
413 pump->ScheduleWork();
414 }
415
SetNestableTasksAllowed(bool allowed)416 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
417 if (nestable_tasks_allowed_ != allowed) {
418 nestable_tasks_allowed_ = allowed;
419 if (!nestable_tasks_allowed_) return;
420 // Start the native pump if we are not already pumping.
421 pump_->ScheduleWorkForNestedLoop();
422 }
423 }
424
ScheduleWork()425 void MessageLoop::ScheduleWork() {
426 // Start the native pump if we are not already pumping.
427 pump_->ScheduleWork();
428 }
429
NestableTasksAllowed() const430 bool MessageLoop::NestableTasksAllowed() const {
431 return nestable_tasks_allowed_;
432 }
433
434 //------------------------------------------------------------------------------
435
RunTask(already_AddRefed<nsIRunnable> aTask)436 void MessageLoop::RunTask(already_AddRefed<nsIRunnable> aTask) {
437 DCHECK(nestable_tasks_allowed_);
438 // Execute the task and assume the worst: It is probably not reentrant.
439 nestable_tasks_allowed_ = false;
440
441 nsCOMPtr<nsIRunnable> task = aTask;
442 task->Run();
443 task = nullptr;
444
445 nestable_tasks_allowed_ = true;
446 }
447
DeferOrRunPendingTask(PendingTask && pending_task)448 bool MessageLoop::DeferOrRunPendingTask(PendingTask&& pending_task) {
449 if (pending_task.nestable || state_->run_depth <= run_depth_base_) {
450 RunTask(pending_task.task.forget());
451 // Show that we ran a task (Note: a new one might arrive as a
452 // consequence!).
453 return true;
454 }
455
456 // We couldn't run the task now because we're in a nested message loop
457 // and the task isn't nestable.
458 deferred_non_nestable_work_queue_.push(std::move(pending_task));
459 return false;
460 }
461
AddToDelayedWorkQueue(const PendingTask & pending_task)462 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
463 // Move to the delayed work queue. Initialize the sequence number
464 // before inserting into the delayed_work_queue_. The sequence number
465 // is used to faciliate FIFO sorting when two tasks have the same
466 // delayed_run_time value.
467 PendingTask new_pending_task(pending_task);
468 new_pending_task.sequence_num = next_sequence_num_++;
469 delayed_work_queue_.push(std::move(new_pending_task));
470 }
471
ReloadWorkQueue()472 void MessageLoop::ReloadWorkQueue() {
473 // We can improve performance of our loading tasks from incoming_queue_ to
474 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
475 // load. That reduces the number of locks-per-task significantly when our
476 // queues get large.
477 if (!work_queue_.empty())
478 return; // Wait till we *really* need to lock and load.
479
480 // Acquire all we can from the inter-thread queue with one lock acquisition.
481 {
482 mozilla::MutexAutoLock lock(incoming_queue_lock_);
483 if (incoming_queue_.empty()) return;
484 std::swap(incoming_queue_, work_queue_);
485 DCHECK(incoming_queue_.empty());
486 }
487 }
488
DeletePendingTasks()489 bool MessageLoop::DeletePendingTasks() {
490 MOZ_ASSERT(work_queue_.empty());
491 bool did_work = !deferred_non_nestable_work_queue_.empty();
492 while (!deferred_non_nestable_work_queue_.empty()) {
493 deferred_non_nestable_work_queue_.pop();
494 }
495 did_work |= !delayed_work_queue_.empty();
496 while (!delayed_work_queue_.empty()) {
497 delayed_work_queue_.pop();
498 }
499 return did_work;
500 }
501
DoWork()502 bool MessageLoop::DoWork() {
503 if (!nestable_tasks_allowed_) {
504 // Task can't be executed right now.
505 return false;
506 }
507
508 for (;;) {
509 ReloadWorkQueue();
510 if (work_queue_.empty()) break;
511
512 // Execute oldest task.
513 do {
514 PendingTask pending_task = std::move(work_queue_.front());
515 work_queue_.pop();
516 if (!pending_task.delayed_run_time.is_null()) {
517 // NB: Don't move, because we use this later!
518 AddToDelayedWorkQueue(pending_task);
519 // If we changed the topmost task, then it is time to re-schedule.
520 if (delayed_work_queue_.top().task == pending_task.task)
521 pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
522 } else {
523 if (DeferOrRunPendingTask(std::move(pending_task))) return true;
524 }
525 } while (!work_queue_.empty());
526 }
527
528 // Nothing happened.
529 return false;
530 }
531
DoDelayedWork(TimeTicks * next_delayed_work_time)532 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
533 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
534 *next_delayed_work_time = TimeTicks();
535 return false;
536 }
537
538 if (delayed_work_queue_.top().delayed_run_time > TimeTicks::Now()) {
539 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
540 return false;
541 }
542
543 PendingTask pending_task = delayed_work_queue_.top();
544 delayed_work_queue_.pop();
545
546 if (!delayed_work_queue_.empty())
547 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
548
549 return DeferOrRunPendingTask(std::move(pending_task));
550 }
551
DoIdleWork()552 bool MessageLoop::DoIdleWork() {
553 if (ProcessNextDelayedNonNestableTask()) return true;
554
555 if (state_->quit_received) pump_->Quit();
556
557 return false;
558 }
559
560 //------------------------------------------------------------------------------
561 // MessageLoop::AutoRunState
562
AutoRunState(MessageLoop * loop)563 MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
564 // Top-level Run should only get called once.
565 MOZ_ASSERT(!loop_->shutting_down_);
566
567 // Make the loop reference us.
568 previous_state_ = loop_->state_;
569 if (previous_state_) {
570 run_depth = previous_state_->run_depth + 1;
571 } else {
572 run_depth = 1;
573 }
574 loop_->state_ = this;
575
576 // Initialize the other fields:
577 quit_received = false;
578 #if defined(OS_WIN)
579 dispatcher = NULL;
580 #endif
581 }
582
~AutoRunState()583 MessageLoop::AutoRunState::~AutoRunState() {
584 loop_->state_ = previous_state_;
585
586 // If exiting a top-level Run, then we're shutting down.
587 loop_->shutting_down_ = !previous_state_;
588 }
589
590 //------------------------------------------------------------------------------
591 // MessageLoop::PendingTask
592
operator <(const PendingTask & other) const593 bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
594 // Since the top of a priority queue is defined as the "greatest" element, we
595 // need to invert the comparison here. We want the smaller time to be at the
596 // top of the heap.
597
598 if (delayed_run_time < other.delayed_run_time) return false;
599
600 if (delayed_run_time > other.delayed_run_time) return true;
601
602 // If the times happen to match, then we use the sequence number to decide.
603 // Compare the difference to support integer roll-over.
604 return (sequence_num - other.sequence_num) > 0;
605 }
606
607 //------------------------------------------------------------------------------
608 // MessageLoop::SerialEventTarget
609
SerialEventTarget()610 nsISerialEventTarget* MessageLoop::SerialEventTarget() { return mEventTarget; }
611
612 //------------------------------------------------------------------------------
613 // MessageLoopForUI
614
615 #if defined(OS_WIN)
616
Run(Dispatcher * dispatcher)617 void MessageLoopForUI::Run(Dispatcher* dispatcher) {
618 AutoRunState save_state(this);
619 state_->dispatcher = dispatcher;
620 RunHandler();
621 }
622
AddObserver(Observer * observer)623 void MessageLoopForUI::AddObserver(Observer* observer) {
624 pump_win()->AddObserver(observer);
625 }
626
RemoveObserver(Observer * observer)627 void MessageLoopForUI::RemoveObserver(Observer* observer) {
628 pump_win()->RemoveObserver(observer);
629 }
630
WillProcessMessage(const MSG & message)631 void MessageLoopForUI::WillProcessMessage(const MSG& message) {
632 pump_win()->WillProcessMessage(message);
633 }
DidProcessMessage(const MSG & message)634 void MessageLoopForUI::DidProcessMessage(const MSG& message) {
635 pump_win()->DidProcessMessage(message);
636 }
PumpOutPendingPaintMessages()637 void MessageLoopForUI::PumpOutPendingPaintMessages() {
638 pump_ui()->PumpOutPendingPaintMessages();
639 }
640
641 #endif // defined(OS_WIN)
642
643 //------------------------------------------------------------------------------
644 // MessageLoopForIO
645
646 #if defined(OS_WIN)
647
RegisterIOHandler(HANDLE file,IOHandler * handler)648 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
649 pump_io()->RegisterIOHandler(file, handler);
650 }
651
WaitForIOCompletion(DWORD timeout,IOHandler * filter)652 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
653 return pump_io()->WaitForIOCompletion(timeout, filter);
654 }
655
656 #elif defined(OS_POSIX)
657
WatchFileDescriptor(int fd,bool persistent,Mode mode,FileDescriptorWatcher * controller,Watcher * delegate)658 bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode,
659 FileDescriptorWatcher* controller,
660 Watcher* delegate) {
661 return pump_libevent()->WatchFileDescriptor(
662 fd, persistent, static_cast<base::MessagePumpLibevent::Mode>(mode),
663 controller, delegate);
664 }
665
CatchSignal(int sig,SignalEvent * sigevent,SignalWatcher * delegate)666 bool MessageLoopForIO::CatchSignal(int sig, SignalEvent* sigevent,
667 SignalWatcher* delegate) {
668 return pump_libevent()->CatchSignal(sig, sigevent, delegate);
669 }
670
671 #endif
672