Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / ipc / chromium / src / base / message_loop.cc
blobc82d555ee551ef2e8e714ea08cc9d3a631aa2cdc
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.
7 #include "base/message_loop.h"
9 #include <algorithm>
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/message_pump_default.h"
14 #include "base/string_util.h"
15 #include "base/thread_local.h"
16 #include "mozilla/Atomics.h"
17 #include "mozilla/Mutex.h"
18 #include "mozilla/ProfilerRunnable.h"
19 #include "nsIEventTarget.h"
20 #include "nsITargetShutdownTask.h"
21 #include "nsThreadUtils.h"
23 #if defined(XP_DARWIN)
24 # include "base/message_pump_mac.h"
25 #endif
26 #if defined(XP_UNIX)
27 # include "base/message_pump_libevent.h"
28 #endif
29 #if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
30 defined(XP_NETBSD) || defined(XP_OPENBSD)
31 # if defined(MOZ_WIDGET_GTK)
32 # include "base/message_pump_glib.h"
33 # endif
34 #endif
35 #ifdef ANDROID
36 # include "base/message_pump_android.h"
37 #endif
38 #include "nsISerialEventTarget.h"
40 #include "mozilla/ipc/MessagePump.h"
41 #include "nsThreadUtils.h"
43 using base::Time;
44 using base::TimeDelta;
45 using base::TimeTicks;
47 using mozilla::Runnable;
49 static base::ThreadLocalPointer<MessageLoop>& get_tls_ptr() {
50 static base::ThreadLocalPointer<MessageLoop> tls_ptr;
51 return tls_ptr;
54 //------------------------------------------------------------------------------
56 #if defined(XP_WIN)
58 // Upon a SEH exception in this thread, it restores the original unhandled
59 // exception filter.
60 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
61 ::SetUnhandledExceptionFilter(old_filter);
62 return EXCEPTION_CONTINUE_SEARCH;
65 // Retrieves a pointer to the current unhandled exception filter. There
66 // is no standalone getter method.
67 static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
68 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
69 top_filter = ::SetUnhandledExceptionFilter(0);
70 ::SetUnhandledExceptionFilter(top_filter);
71 return top_filter;
74 #endif // defined(XP_WIN)
76 //------------------------------------------------------------------------------
78 class MessageLoop::EventTarget : public nsISerialEventTarget,
79 public nsITargetShutdownTask,
80 public MessageLoop::DestructionObserver {
81 public:
82 NS_DECL_THREADSAFE_ISUPPORTS
83 NS_DECL_NSIEVENTTARGET_FULL
85 void TargetShutdown() override {
86 nsTArray<nsCOMPtr<nsITargetShutdownTask>> shutdownTasks;
88 mozilla::MutexAutoLock lock(mMutex);
89 if (mShutdownTasksRun) {
90 return;
92 mShutdownTasksRun = true;
93 shutdownTasks = std::move(mShutdownTasks);
94 mShutdownTasks.Clear();
97 for (auto& task : shutdownTasks) {
98 task->TargetShutdown();
102 explicit EventTarget(MessageLoop* aLoop)
103 : mMutex("MessageLoop::EventTarget"), mLoop(aLoop) {
104 aLoop->AddDestructionObserver(this);
107 private:
108 virtual ~EventTarget() {
109 if (mLoop) {
110 mLoop->RemoveDestructionObserver(this);
112 MOZ_ASSERT(mShutdownTasks.IsEmpty());
115 void WillDestroyCurrentMessageLoop() override {
117 mozilla::MutexAutoLock lock(mMutex);
118 // The MessageLoop is being destroyed and we are called from its
119 // destructor There's no real need to remove ourselves from the
120 // destruction observer list. But it makes things look tidier.
121 mLoop->RemoveDestructionObserver(this);
122 mLoop = nullptr;
125 TargetShutdown();
128 mozilla::Mutex mMutex;
129 bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false;
130 nsTArray<nsCOMPtr<nsITargetShutdownTask>> mShutdownTasks
131 MOZ_GUARDED_BY(mMutex);
132 MessageLoop* mLoop MOZ_GUARDED_BY(mMutex);
135 NS_IMPL_ISUPPORTS(MessageLoop::EventTarget, nsIEventTarget,
136 nsISerialEventTarget)
138 NS_IMETHODIMP_(bool)
139 MessageLoop::EventTarget::IsOnCurrentThreadInfallible() {
140 mozilla::MutexAutoLock lock(mMutex);
141 return mLoop == MessageLoop::current();
144 NS_IMETHODIMP
145 MessageLoop::EventTarget::IsOnCurrentThread(bool* aResult) {
146 *aResult = IsOnCurrentThreadInfallible();
147 return NS_OK;
150 NS_IMETHODIMP
151 MessageLoop::EventTarget::DispatchFromScript(nsIRunnable* aEvent,
152 uint32_t aFlags) {
153 nsCOMPtr<nsIRunnable> event(aEvent);
154 return Dispatch(event.forget(), aFlags);
157 NS_IMETHODIMP
158 MessageLoop::EventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
159 uint32_t aFlags) {
160 mozilla::MutexAutoLock lock(mMutex);
161 if (!mLoop) {
162 return NS_ERROR_NOT_INITIALIZED;
165 if (aFlags != NS_DISPATCH_NORMAL) {
166 return NS_ERROR_NOT_IMPLEMENTED;
169 mLoop->PostTask(std::move(aEvent));
170 return NS_OK;
173 NS_IMETHODIMP
174 MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
175 uint32_t aDelayMs) {
176 mozilla::MutexAutoLock lock(mMutex);
177 if (!mLoop) {
178 return NS_ERROR_NOT_INITIALIZED;
181 mLoop->PostDelayedTask(std::move(aEvent), aDelayMs);
182 return NS_OK;
185 NS_IMETHODIMP
186 MessageLoop::EventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
187 mozilla::MutexAutoLock lock(mMutex);
188 if (!mLoop || mShutdownTasksRun) {
189 return NS_ERROR_UNEXPECTED;
191 MOZ_ASSERT(!mShutdownTasks.Contains(aTask));
192 mShutdownTasks.AppendElement(aTask);
193 return NS_OK;
196 NS_IMETHODIMP
197 MessageLoop::EventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) {
198 mozilla::MutexAutoLock lock(mMutex);
199 if (!mLoop || mShutdownTasksRun) {
200 return NS_ERROR_UNEXPECTED;
202 return mShutdownTasks.RemoveElement(aTask) ? NS_OK : NS_ERROR_UNEXPECTED;
205 //------------------------------------------------------------------------------
207 // static
208 MessageLoop* MessageLoop::current() { return get_tls_ptr().Get(); }
210 // static
211 void MessageLoop::set_current(MessageLoop* loop) { get_tls_ptr().Set(loop); }
213 static mozilla::Atomic<int32_t> message_loop_id_seq(0);
215 MessageLoop::MessageLoop(Type type, nsISerialEventTarget* aEventTarget)
216 : type_(type),
217 id_(++message_loop_id_seq),
218 nestable_tasks_allowed_(true),
219 exception_restoration_(false),
220 incoming_queue_lock_("MessageLoop Incoming Queue Lock"),
221 state_(NULL),
222 run_depth_base_(1),
223 shutting_down_(false),
224 #ifdef XP_WIN
225 os_modal_loop_(false),
226 #endif // XP_WIN
227 transient_hang_timeout_(0),
228 permanent_hang_timeout_(0),
229 next_sequence_num_(0) {
230 DCHECK(!current()) << "should only have one message loop per thread";
231 get_tls_ptr().Set(this);
233 // Must initialize after current() is initialized.
234 mEventTarget = new EventTarget(this);
236 switch (type_) {
237 case TYPE_MOZILLA_PARENT:
238 MOZ_RELEASE_ASSERT(!aEventTarget);
239 pump_ = new mozilla::ipc::MessagePump(aEventTarget);
240 return;
241 case TYPE_MOZILLA_CHILD:
242 MOZ_RELEASE_ASSERT(!aEventTarget);
243 pump_ = new mozilla::ipc::MessagePumpForChildProcess();
244 // There is a MessageLoop Run call from XRE_InitChildProcess
245 // and another one from MessagePumpForChildProcess. The one
246 // from MessagePumpForChildProcess becomes the base, so we need
247 // to set run_depth_base_ to 2 or we'll never be able to process
248 // Idle tasks.
249 run_depth_base_ = 2;
250 return;
251 case TYPE_MOZILLA_NONMAINTHREAD:
252 pump_ = new mozilla::ipc::MessagePumpForNonMainThreads(aEventTarget);
253 return;
254 #if defined(XP_WIN) || defined(XP_DARWIN)
255 case TYPE_MOZILLA_NONMAINUITHREAD:
256 pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aEventTarget);
257 return;
258 #elif defined(MOZ_WIDGET_ANDROID)
259 case TYPE_MOZILLA_ANDROID_UI:
260 MOZ_RELEASE_ASSERT(aEventTarget);
261 pump_ = new mozilla::ipc::MessagePumpForAndroidUI(aEventTarget);
262 return;
263 #endif // defined(MOZ_WIDGET_ANDROID)
264 default:
265 // Create one of Chromium's standard MessageLoop types below.
266 break;
269 #if defined(XP_WIN)
270 // TODO(rvargas): Get rid of the OS guards.
271 if (type_ == TYPE_DEFAULT) {
272 pump_ = new base::MessagePumpDefault();
273 } else if (type_ == TYPE_IO) {
274 pump_ = new base::MessagePumpForIO();
275 } else {
276 DCHECK(type_ == TYPE_UI);
277 pump_ = new base::MessagePumpForUI();
279 #else
280 if (type_ == TYPE_UI) {
281 # if defined(XP_DARWIN)
282 pump_ = base::MessagePumpMac::Create();
283 # elif defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
284 defined(XP_NETBSD) || defined(XP_OPENBSD)
285 pump_ = new base::MessagePumpForUI();
286 # endif // XP_LINUX
287 } else if (type_ == TYPE_IO) {
288 pump_ = new base::MessagePumpLibevent();
289 } else {
290 pump_ = new base::MessagePumpDefault();
292 #endif
294 // We want GetCurrentSerialEventTarget() to return the real nsThread if it
295 // will be used to dispatch tasks. However, under all other cases; we'll want
296 // it to return this MessageLoop's EventTarget.
297 if (nsISerialEventTarget* thread = pump_->GetXPCOMThread()) {
298 MOZ_ALWAYS_SUCCEEDS(thread->RegisterShutdownTask(mEventTarget));
299 } else {
300 mozilla::SerialEventTargetGuard::Set(mEventTarget);
304 MessageLoop::~MessageLoop() {
305 DCHECK(this == current());
307 // Let interested parties have one last shot at accessing this.
308 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
309 WillDestroyCurrentMessageLoop());
311 DCHECK(!state_);
313 // Clean up any unprocessed tasks, but take care: deleting a task could
314 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
315 // limit on the number of times we will allow a deleted task to generate more
316 // tasks. Normally, we should only pass through this loop once or twice. If
317 // we end up hitting the loop limit, then it is probably due to one task that
318 // is being stubborn. Inspect the queues to see who is left.
319 bool did_work;
320 for (int i = 0; i < 100; ++i) {
321 DeletePendingTasks();
322 ReloadWorkQueue();
323 // If we end up with empty queues, then break out of the loop.
324 did_work = DeletePendingTasks();
325 if (!did_work) break;
327 DCHECK(!did_work);
329 // OK, now make it so that no one can find us.
330 get_tls_ptr().Set(NULL);
333 void MessageLoop::AddDestructionObserver(DestructionObserver* obs) {
334 DCHECK(this == current());
335 destruction_observers_.AddObserver(obs);
338 void MessageLoop::RemoveDestructionObserver(DestructionObserver* obs) {
339 DCHECK(this == current());
340 destruction_observers_.RemoveObserver(obs);
343 void MessageLoop::Run() {
344 AutoRunState save_state(this);
345 RunHandler();
348 // Runs the loop in two different SEH modes:
349 // enable_SEH_restoration_ = false : any unhandled exception goes to the last
350 // one that calls SetUnhandledExceptionFilter().
351 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter
352 // that was existed before the loop was run.
353 void MessageLoop::RunHandler() {
354 #if defined(XP_WIN)
355 if (exception_restoration_) {
356 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
357 MOZ_SEH_TRY { RunInternal(); }
358 MOZ_SEH_EXCEPT(SEHFilter(current_filter)) {}
359 return;
361 #endif
363 RunInternal();
366 //------------------------------------------------------------------------------
368 void MessageLoop::RunInternal() {
369 DCHECK(this == current());
370 pump_->Run(this);
373 //------------------------------------------------------------------------------
374 // Wrapper functions for use in above message loop framework.
376 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
377 if (state_->run_depth > run_depth_base_) return false;
379 if (deferred_non_nestable_work_queue_.empty()) return false;
381 nsCOMPtr<nsIRunnable> task =
382 std::move(deferred_non_nestable_work_queue_.front().task);
383 deferred_non_nestable_work_queue_.pop();
385 RunTask(task.forget());
386 return true;
389 //------------------------------------------------------------------------------
391 void MessageLoop::Quit() {
392 DCHECK(current() == this);
393 if (state_) {
394 state_->quit_received = true;
395 } else {
396 NOTREACHED() << "Must be inside Run to call Quit";
400 void MessageLoop::PostTask(already_AddRefed<nsIRunnable> task) {
401 PostTask_Helper(std::move(task), 0);
404 void MessageLoop::PostDelayedTask(already_AddRefed<nsIRunnable> task,
405 int delay_ms) {
406 PostTask_Helper(std::move(task), delay_ms);
409 void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
410 DCHECK(current() == this);
411 MOZ_ASSERT(NS_IsMainThread());
413 PendingTask pending_task(std::move(task), false);
414 mozilla::LogRunnable::LogDispatch(pending_task.task.get());
415 deferred_non_nestable_work_queue_.push(std::move(pending_task));
418 // Possibly called on a background thread!
419 void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task,
420 int delay_ms) {
421 if (nsISerialEventTarget* target = pump_->GetXPCOMThread()) {
422 nsresult rv;
423 if (delay_ms) {
424 rv = target->DelayedDispatch(std::move(task), delay_ms);
425 } else {
426 rv = target->Dispatch(std::move(task), 0);
428 MOZ_ALWAYS_SUCCEEDS(rv);
429 return;
432 // Tasks should only be queued before or during the Run loop, not after.
433 MOZ_ASSERT(!shutting_down_);
435 PendingTask pending_task(std::move(task), true);
437 if (delay_ms > 0) {
438 pending_task.delayed_run_time =
439 TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
440 } else {
441 DCHECK(delay_ms == 0) << "delay should not be negative";
444 // Warning: Don't try to short-circuit, and handle this thread's tasks more
445 // directly, as it could starve handling of foreign threads. Put every task
446 // into this queue.
448 RefPtr<base::MessagePump> pump;
450 mozilla::MutexAutoLock locked(incoming_queue_lock_);
451 mozilla::LogRunnable::LogDispatch(pending_task.task.get());
452 incoming_queue_.push(std::move(pending_task));
453 pump = pump_;
455 // Since the incoming_queue_ may contain a task that destroys this message
456 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
457 // We use a stack-based reference to the message pump so that we can call
458 // ScheduleWork outside of incoming_queue_lock_.
460 pump->ScheduleWork();
463 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
464 if (nestable_tasks_allowed_ != allowed) {
465 nestable_tasks_allowed_ = allowed;
466 if (!nestable_tasks_allowed_) return;
467 // Start the native pump if we are not already pumping.
468 pump_->ScheduleWorkForNestedLoop();
472 void MessageLoop::ScheduleWork() {
473 // Start the native pump if we are not already pumping.
474 pump_->ScheduleWork();
477 bool MessageLoop::NestableTasksAllowed() const {
478 return nestable_tasks_allowed_;
481 //------------------------------------------------------------------------------
483 void MessageLoop::RunTask(already_AddRefed<nsIRunnable> aTask) {
484 DCHECK(nestable_tasks_allowed_);
485 // Execute the task and assume the worst: It is probably not reentrant.
486 nestable_tasks_allowed_ = false;
488 nsCOMPtr<nsIRunnable> task = aTask;
491 mozilla::LogRunnable::Run log(task.get());
492 AUTO_PROFILE_FOLLOWING_RUNNABLE(task);
493 task->Run();
494 task = nullptr;
497 nestable_tasks_allowed_ = true;
500 bool MessageLoop::DeferOrRunPendingTask(PendingTask&& pending_task) {
501 if (pending_task.nestable || state_->run_depth <= run_depth_base_) {
502 RunTask(pending_task.task.forget());
503 // Show that we ran a task (Note: a new one might arrive as a
504 // consequence!).
505 return true;
508 // We couldn't run the task now because we're in a nested message loop
509 // and the task isn't nestable.
510 mozilla::LogRunnable::LogDispatch(pending_task.task.get());
511 deferred_non_nestable_work_queue_.push(std::move(pending_task));
512 return false;
515 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
516 // Move to the delayed work queue. Initialize the sequence number
517 // before inserting into the delayed_work_queue_. The sequence number
518 // is used to faciliate FIFO sorting when two tasks have the same
519 // delayed_run_time value.
520 PendingTask new_pending_task(pending_task);
521 new_pending_task.sequence_num = next_sequence_num_++;
522 mozilla::LogRunnable::LogDispatch(new_pending_task.task.get());
523 delayed_work_queue_.push(std::move(new_pending_task));
526 void MessageLoop::ReloadWorkQueue() {
527 // We can improve performance of our loading tasks from incoming_queue_ to
528 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
529 // load. That reduces the number of locks-per-task significantly when our
530 // queues get large.
531 if (!work_queue_.empty())
532 return; // Wait till we *really* need to lock and load.
534 // Acquire all we can from the inter-thread queue with one lock acquisition.
536 mozilla::MutexAutoLock lock(incoming_queue_lock_);
537 if (incoming_queue_.empty()) return;
538 std::swap(incoming_queue_, work_queue_);
539 DCHECK(incoming_queue_.empty());
543 bool MessageLoop::DeletePendingTasks() {
544 MOZ_ASSERT(work_queue_.empty());
545 bool did_work = !deferred_non_nestable_work_queue_.empty();
546 while (!deferred_non_nestable_work_queue_.empty()) {
547 deferred_non_nestable_work_queue_.pop();
549 did_work |= !delayed_work_queue_.empty();
550 while (!delayed_work_queue_.empty()) {
551 delayed_work_queue_.pop();
553 return did_work;
556 bool MessageLoop::DoWork() {
557 if (!nestable_tasks_allowed_) {
558 // Task can't be executed right now.
559 return false;
562 for (;;) {
563 ReloadWorkQueue();
564 if (work_queue_.empty()) break;
566 // Execute oldest task.
567 do {
568 PendingTask pending_task = std::move(work_queue_.front());
569 work_queue_.pop();
570 if (!pending_task.delayed_run_time.is_null()) {
571 // NB: Don't move, because we use this later!
572 AddToDelayedWorkQueue(pending_task);
573 // If we changed the topmost task, then it is time to re-schedule.
574 if (delayed_work_queue_.top().task == pending_task.task)
575 pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
576 } else {
577 if (DeferOrRunPendingTask(std::move(pending_task))) return true;
579 } while (!work_queue_.empty());
582 // Nothing happened.
583 return false;
586 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
587 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
588 *next_delayed_work_time = TimeTicks();
589 return false;
592 if (delayed_work_queue_.top().delayed_run_time > TimeTicks::Now()) {
593 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
594 return false;
597 PendingTask pending_task = delayed_work_queue_.top();
598 delayed_work_queue_.pop();
600 if (!delayed_work_queue_.empty())
601 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
603 return DeferOrRunPendingTask(std::move(pending_task));
606 bool MessageLoop::DoIdleWork() {
607 if (ProcessNextDelayedNonNestableTask()) return true;
609 if (state_->quit_received) pump_->Quit();
611 return false;
614 //------------------------------------------------------------------------------
615 // MessageLoop::AutoRunState
617 MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
618 // Top-level Run should only get called once.
619 MOZ_ASSERT(!loop_->shutting_down_);
621 // Make the loop reference us.
622 previous_state_ = loop_->state_;
623 if (previous_state_) {
624 run_depth = previous_state_->run_depth + 1;
625 } else {
626 run_depth = 1;
628 loop_->state_ = this;
630 // Initialize the other fields:
631 quit_received = false;
632 #if defined(XP_WIN)
633 dispatcher = NULL;
634 #endif
637 MessageLoop::AutoRunState::~AutoRunState() {
638 loop_->state_ = previous_state_;
640 // If exiting a top-level Run, then we're shutting down.
641 loop_->shutting_down_ = !previous_state_;
644 //------------------------------------------------------------------------------
645 // MessageLoop::PendingTask
647 bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
648 // Since the top of a priority queue is defined as the "greatest" element, we
649 // need to invert the comparison here. We want the smaller time to be at the
650 // top of the heap.
652 if (delayed_run_time < other.delayed_run_time) return false;
654 if (delayed_run_time > other.delayed_run_time) return true;
656 // If the times happen to match, then we use the sequence number to decide.
657 // Compare the difference to support integer roll-over.
658 return (sequence_num - other.sequence_num) > 0;
661 //------------------------------------------------------------------------------
662 // MessageLoop::SerialEventTarget
664 nsISerialEventTarget* MessageLoop::SerialEventTarget() { return mEventTarget; }
666 //------------------------------------------------------------------------------
667 // MessageLoopForUI
669 #if defined(XP_WIN)
671 void MessageLoopForUI::Run(Dispatcher* dispatcher) {
672 AutoRunState save_state(this);
673 state_->dispatcher = dispatcher;
674 RunHandler();
677 void MessageLoopForUI::AddObserver(Observer* observer) {
678 pump_win()->AddObserver(observer);
681 void MessageLoopForUI::RemoveObserver(Observer* observer) {
682 pump_win()->RemoveObserver(observer);
685 void MessageLoopForUI::WillProcessMessage(const MSG& message) {
686 pump_win()->WillProcessMessage(message);
688 void MessageLoopForUI::DidProcessMessage(const MSG& message) {
689 pump_win()->DidProcessMessage(message);
691 void MessageLoopForUI::PumpOutPendingPaintMessages() {
692 pump_ui()->PumpOutPendingPaintMessages();
695 #endif // defined(XP_WIN)
697 //------------------------------------------------------------------------------
698 // MessageLoopForIO
700 #if defined(XP_WIN)
702 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
703 pump_io()->RegisterIOHandler(file, handler);
706 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
707 return pump_io()->WaitForIOCompletion(timeout, filter);
710 #else
712 bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode,
713 FileDescriptorWatcher* controller,
714 Watcher* delegate) {
715 return pump_libevent()->WatchFileDescriptor(
716 fd, persistent, static_cast<base::MessagePumpLibevent::Mode>(mode),
717 controller, delegate);
720 bool MessageLoopForIO::CatchSignal(int sig, SignalEvent* sigevent,
721 SignalWatcher* delegate) {
722 return pump_libevent()->CatchSignal(sig, sigevent, delegate);
725 #endif