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