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