Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_MESSAGE_LOOP_H_
      6 #define BASE_MESSAGE_LOOP_H_
      7 #pragma once
      8 
      9 #include <queue>
     10 #include <string>
     11 
     12 #include "base/base_api.h"
     13 #include "base/basictypes.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/message_pump.h"
     16 #include "base/observer_list.h"
     17 #include "base/synchronization/lock.h"
     18 #include "base/task.h"
     19 
     20 #if defined(OS_WIN)
     21 // We need this to declare base::MessagePumpWin::Dispatcher, which we should
     22 // really just eliminate.
     23 #include "base/message_pump_win.h"
     24 #elif defined(OS_POSIX)
     25 #include "base/message_pump_libevent.h"
     26 #if !defined(OS_MACOSX)
     27 #include "base/message_pump_glib.h"
     28 typedef struct _XDisplay Display;
     29 #endif
     30 #endif
     31 #if defined(TOUCH_UI)
     32 #include "base/message_pump_glib_x_dispatch.h"
     33 #endif
     34 
     35 namespace base {
     36 class Histogram;
     37 }
     38 
     39 // A MessageLoop is used to process events for a particular thread.  There is
     40 // at most one MessageLoop instance per thread.
     41 //
     42 // Events include at a minimum Task instances submitted to PostTask or those
     43 // managed by TimerManager.  Depending on the type of message pump used by the
     44 // MessageLoop other events such as UI messages may be processed.  On Windows
     45 // APC calls (as time permits) and signals sent to a registered set of HANDLEs
     46 // may also be processed.
     47 //
     48 // NOTE: Unless otherwise specified, a MessageLoop's methods may only be called
     49 // on the thread where the MessageLoop's Run method executes.
     50 //
     51 // NOTE: MessageLoop has task reentrancy protection.  This means that if a
     52 // task is being processed, a second task cannot start until the first task is
     53 // finished.  Reentrancy can happen when processing a task, and an inner
     54 // message pump is created.  That inner pump then processes native messages
     55 // which could implicitly start an inner task.  Inner message pumps are created
     56 // with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions
     57 // (DoDragDrop), printer functions (StartDoc) and *many* others.
     58 //
     59 // Sample workaround when inner task processing is needed:
     60 //   bool old_state = MessageLoop::current()->NestableTasksAllowed();
     61 //   MessageLoop::current()->SetNestableTasksAllowed(true);
     62 //   HRESULT hr = DoDragDrop(...); // Implicitly runs a modal message loop here.
     63 //   MessageLoop::current()->SetNestableTasksAllowed(old_state);
     64 //   // Process hr  (the result returned by DoDragDrop().
     65 //
     66 // Please be SURE your task is reentrant (nestable) and all global variables
     67 // are stable and accessible before calling SetNestableTasksAllowed(true).
     68 //
     69 class BASE_API MessageLoop : public base::MessagePump::Delegate {
     70  public:
     71 #if defined(OS_WIN)
     72   typedef base::MessagePumpWin::Dispatcher Dispatcher;
     73   typedef base::MessagePumpForUI::Observer Observer;
     74 #elif !defined(OS_MACOSX)
     75 #if defined(TOUCH_UI)
     76   typedef base::MessagePumpGlibXDispatcher Dispatcher;
     77 #else
     78   typedef base::MessagePumpForUI::Dispatcher Dispatcher;
     79 #endif
     80   typedef base::MessagePumpForUI::Observer Observer;
     81 #endif
     82 
     83   // A MessageLoop has a particular type, which indicates the set of
     84   // asynchronous events it may process in addition to tasks and timers.
     85   //
     86   // TYPE_DEFAULT
     87   //   This type of ML only supports tasks and timers.
     88   //
     89   // TYPE_UI
     90   //   This type of ML also supports native UI events (e.g., Windows messages).
     91   //   See also MessageLoopForUI.
     92   //
     93   // TYPE_IO
     94   //   This type of ML also supports asynchronous IO.  See also
     95   //   MessageLoopForIO.
     96   //
     97   enum Type {
     98     TYPE_DEFAULT,
     99     TYPE_UI,
    100     TYPE_IO
    101   };
    102 
    103   // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
    104   // is typical to make use of the current thread's MessageLoop instance.
    105   explicit MessageLoop(Type type = TYPE_DEFAULT);
    106   ~MessageLoop();
    107 
    108   // Returns the MessageLoop object for the current thread, or null if none.
    109   static MessageLoop* current();
    110 
    111   static void EnableHistogrammer(bool enable_histogrammer);
    112 
    113   // A DestructionObserver is notified when the current MessageLoop is being
    114   // destroyed.  These obsevers are notified prior to MessageLoop::current()
    115   // being changed to return NULL.  This gives interested parties the chance to
    116   // do final cleanup that depends on the MessageLoop.
    117   //
    118   // NOTE: Any tasks posted to the MessageLoop during this notification will
    119   // not be run.  Instead, they will be deleted.
    120   //
    121   class BASE_API DestructionObserver {
    122    public:
    123     virtual void WillDestroyCurrentMessageLoop() = 0;
    124 
    125    protected:
    126     virtual ~DestructionObserver();
    127   };
    128 
    129   // Add a DestructionObserver, which will start receiving notifications
    130   // immediately.
    131   void AddDestructionObserver(DestructionObserver* destruction_observer);
    132 
    133   // Remove a DestructionObserver.  It is safe to call this method while a
    134   // DestructionObserver is receiving a notification callback.
    135   void RemoveDestructionObserver(DestructionObserver* destruction_observer);
    136 
    137   // The "PostTask" family of methods call the task's Run method asynchronously
    138   // from within a message loop at some point in the future.
    139   //
    140   // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed
    141   // with normal UI or IO event processing.  With the PostDelayedTask variant,
    142   // tasks are called after at least approximately 'delay_ms' have elapsed.
    143   //
    144   // The NonNestable variants work similarly except that they promise never to
    145   // dispatch the task from a nested invocation of MessageLoop::Run.  Instead,
    146   // such tasks get deferred until the top-most MessageLoop::Run is executing.
    147   //
    148   // The MessageLoop takes ownership of the Task, and deletes it after it has
    149   // been Run().
    150   //
    151   // NOTE: These methods may be called on any thread.  The Task will be invoked
    152   // on the thread that executes MessageLoop::Run().
    153 
    154   void PostTask(
    155       const tracked_objects::Location& from_here, Task* task);
    156 
    157   void PostDelayedTask(
    158       const tracked_objects::Location& from_here, Task* task, int64 delay_ms);
    159 
    160   void PostNonNestableTask(
    161       const tracked_objects::Location& from_here, Task* task);
    162 
    163   void PostNonNestableDelayedTask(
    164       const tracked_objects::Location& from_here, Task* task, int64 delay_ms);
    165 
    166   // A variant on PostTask that deletes the given object.  This is useful
    167   // if the object needs to live until the next run of the MessageLoop (for
    168   // example, deleting a RenderProcessHost from within an IPC callback is not
    169   // good).
    170   //
    171   // NOTE: This method may be called on any thread.  The object will be deleted
    172   // on the thread that executes MessageLoop::Run().  If this is not the same
    173   // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit
    174   // from RefCountedThreadSafe<T>!
    175   template <class T>
    176   void DeleteSoon(const tracked_objects::Location& from_here, const T* object) {
    177     PostNonNestableTask(from_here, new DeleteTask<T>(object));
    178   }
    179 
    180   // A variant on PostTask that releases the given reference counted object
    181   // (by calling its Release method).  This is useful if the object needs to
    182   // live until the next run of the MessageLoop, or if the object needs to be
    183   // released on a particular thread.
    184   //
    185   // NOTE: This method may be called on any thread.  The object will be
    186   // released (and thus possibly deleted) on the thread that executes
    187   // MessageLoop::Run().  If this is not the same as the thread that calls
    188   // PostDelayedTask(FROM_HERE, ), then T MUST inherit from
    189   // RefCountedThreadSafe<T>!
    190   template <class T>
    191   void ReleaseSoon(const tracked_objects::Location& from_here,
    192                    const T* object) {
    193     PostNonNestableTask(from_here, new ReleaseTask<T>(object));
    194   }
    195 
    196   // Run the message loop.
    197   void Run();
    198 
    199   // Process all pending tasks, windows messages, etc., but don't wait/sleep.
    200   // Return as soon as all items that can be run are taken care of.
    201   void RunAllPending();
    202 
    203   // Signals the Run method to return after it is done processing all pending
    204   // messages.  This method may only be called on the same thread that called
    205   // Run, and Run must still be on the call stack.
    206   //
    207   // Use QuitTask if you need to Quit another thread's MessageLoop, but note
    208   // that doing so is fairly dangerous if the target thread makes nested calls
    209   // to MessageLoop::Run.  The problem being that you won't know which nested
    210   // run loop you are quiting, so be careful!
    211   //
    212   void Quit();
    213 
    214   // This method is a variant of Quit, that does not wait for pending messages
    215   // to be processed before returning from Run.
    216   void QuitNow();
    217 
    218   // Invokes Quit on the current MessageLoop when run.  Useful to schedule an
    219   // arbitrary MessageLoop to Quit.
    220   class QuitTask : public Task {
    221    public:
    222     virtual void Run() {
    223       MessageLoop::current()->Quit();
    224     }
    225   };
    226 
    227   // Returns the type passed to the constructor.
    228   Type type() const { return type_; }
    229 
    230   // Optional call to connect the thread name with this loop.
    231   void set_thread_name(const std::string& thread_name) {
    232     DCHECK(thread_name_.empty()) << "Should not rename this thread!";
    233     thread_name_ = thread_name;
    234   }
    235   const std::string& thread_name() const { return thread_name_; }
    236 
    237   // Enables or disables the recursive task processing. This happens in the case
    238   // of recursive message loops. Some unwanted message loop may occurs when
    239   // using common controls or printer functions. By default, recursive task
    240   // processing is disabled.
    241   //
    242   // The specific case where tasks get queued is:
    243   // - The thread is running a message loop.
    244   // - It receives a task #1 and execute it.
    245   // - The task #1 implicitly start a message loop, like a MessageBox in the
    246   //   unit test. This can also be StartDoc or GetSaveFileName.
    247   // - The thread receives a task #2 before or while in this second message
    248   //   loop.
    249   // - With NestableTasksAllowed set to true, the task #2 will run right away.
    250   //   Otherwise, it will get executed right after task #1 completes at "thread
    251   //   message loop level".
    252   void SetNestableTasksAllowed(bool allowed);
    253   bool NestableTasksAllowed() const;
    254 
    255   // Enables nestable tasks on |loop| while in scope.
    256   class ScopedNestableTaskAllower {
    257    public:
    258     explicit ScopedNestableTaskAllower(MessageLoop* loop)
    259         : loop_(loop),
    260           old_state_(loop_->NestableTasksAllowed()) {
    261       loop_->SetNestableTasksAllowed(true);
    262     }
    263     ~ScopedNestableTaskAllower() {
    264       loop_->SetNestableTasksAllowed(old_state_);
    265     }
    266 
    267    private:
    268     MessageLoop* loop_;
    269     bool old_state_;
    270   };
    271 
    272   // Enables or disables the restoration during an exception of the unhandled
    273   // exception filter that was active when Run() was called. This can happen
    274   // if some third party code call SetUnhandledExceptionFilter() and never
    275   // restores the previous filter.
    276   void set_exception_restoration(bool restore) {
    277     exception_restoration_ = restore;
    278   }
    279 
    280   // Returns true if we are currently running a nested message loop.
    281   bool IsNested();
    282 
    283   // A TaskObserver is an object that receives task notifications from the
    284   // MessageLoop.
    285   //
    286   // NOTE: A TaskObserver implementation should be extremely fast!
    287   class BASE_API TaskObserver {
    288    public:
    289     TaskObserver();
    290 
    291     // This method is called before processing a task.
    292     virtual void WillProcessTask(const Task* task) = 0;
    293 
    294     // This method is called after processing a task.
    295     virtual void DidProcessTask(const Task* task) = 0;
    296 
    297    protected:
    298     virtual ~TaskObserver();
    299   };
    300 
    301   // These functions can only be called on the same thread that |this| is
    302   // running on.
    303   void AddTaskObserver(TaskObserver* task_observer);
    304   void RemoveTaskObserver(TaskObserver* task_observer);
    305 
    306   // Returns true if the message loop has high resolution timers enabled.
    307   // Provided for testing.
    308   bool high_resolution_timers_enabled() {
    309 #if defined(OS_WIN)
    310     return !high_resolution_timer_expiration_.is_null();
    311 #else
    312     return true;
    313 #endif
    314   }
    315 
    316   // When we go into high resolution timer mode, we will stay in hi-res mode
    317   // for at least 1s.
    318   static const int kHighResolutionTimerModeLeaseTimeMs = 1000;
    319 
    320   // Asserts that the MessageLoop is "idle".
    321   void AssertIdle() const;
    322 
    323 #if defined(OS_WIN)
    324   void set_os_modal_loop(bool os_modal_loop) {
    325     os_modal_loop_ = os_modal_loop;
    326   }
    327 
    328   bool os_modal_loop() const {
    329     return os_modal_loop_;
    330   }
    331 #endif  // OS_WIN
    332 
    333   //----------------------------------------------------------------------------
    334  protected:
    335   struct RunState {
    336     // Used to count how many Run() invocations are on the stack.
    337     int run_depth;
    338 
    339     // Used to record that Quit() was called, or that we should quit the pump
    340     // once it becomes idle.
    341     bool quit_received;
    342 
    343 #if !defined(OS_MACOSX)
    344     Dispatcher* dispatcher;
    345 #endif
    346   };
    347 
    348   class AutoRunState : RunState {
    349    public:
    350     explicit AutoRunState(MessageLoop* loop);
    351     ~AutoRunState();
    352    private:
    353     MessageLoop* loop_;
    354     RunState* previous_state_;
    355   };
    356 
    357   // This structure is copied around by value.
    358   struct PendingTask {
    359     PendingTask(Task* task, bool nestable)
    360         : task(task), sequence_num(0), nestable(nestable) {
    361     }
    362 
    363     // Used to support sorting.
    364     bool operator<(const PendingTask& other) const;
    365 
    366     Task* task;                        // The task to run.
    367     base::TimeTicks delayed_run_time;  // The time when the task should be run.
    368     int sequence_num;                  // Secondary sort key for run time.
    369     bool nestable;                     // OK to dispatch from a nested loop.
    370   };
    371 
    372   class TaskQueue : public std::queue<PendingTask> {
    373    public:
    374     void Swap(TaskQueue* queue) {
    375       c.swap(queue->c);  // Calls std::deque::swap
    376     }
    377   };
    378 
    379   typedef std::priority_queue<PendingTask> DelayedTaskQueue;
    380 
    381 #if defined(OS_WIN)
    382   base::MessagePumpWin* pump_win() {
    383     return static_cast<base::MessagePumpWin*>(pump_.get());
    384   }
    385 #elif defined(OS_POSIX)
    386   base::MessagePumpLibevent* pump_libevent() {
    387     return static_cast<base::MessagePumpLibevent*>(pump_.get());
    388   }
    389 #endif
    390 
    391   // A function to encapsulate all the exception handling capability in the
    392   // stacks around the running of a main message loop.  It will run the message
    393   // loop in a SEH try block or not depending on the set_SEH_restoration()
    394   // flag invoking respectively RunInternalInSEHFrame() or RunInternal().
    395   void RunHandler();
    396 
    397 #if defined(OS_WIN)
    398   __declspec(noinline) void RunInternalInSEHFrame();
    399 #endif
    400 
    401   // A surrounding stack frame around the running of the message loop that
    402   // supports all saving and restoring of state, as is needed for any/all (ugly)
    403   // recursive calls.
    404   void RunInternal();
    405 
    406   // Called to process any delayed non-nestable tasks.
    407   bool ProcessNextDelayedNonNestableTask();
    408 
    409   // Runs the specified task and deletes it.
    410   void RunTask(Task* task);
    411 
    412   // Calls RunTask or queues the pending_task on the deferred task list if it
    413   // cannot be run right now.  Returns true if the task was run.
    414   bool DeferOrRunPendingTask(const PendingTask& pending_task);
    415 
    416   // Adds the pending task to delayed_work_queue_.
    417   void AddToDelayedWorkQueue(const PendingTask& pending_task);
    418 
    419   // Load tasks from the incoming_queue_ into work_queue_ if the latter is
    420   // empty.  The former requires a lock to access, while the latter is directly
    421   // accessible on this thread.
    422   void ReloadWorkQueue();
    423 
    424   // Delete tasks that haven't run yet without running them.  Used in the
    425   // destructor to make sure all the task's destructors get called.  Returns
    426   // true if some work was done.
    427   bool DeletePendingTasks();
    428 
    429   // Post a task to our incomming queue.
    430   void PostTask_Helper(const tracked_objects::Location& from_here, Task* task,
    431                        int64 delay_ms, bool nestable);
    432 
    433   // Start recording histogram info about events and action IF it was enabled
    434   // and IF the statistics recorder can accept a registration of our histogram.
    435   void StartHistogrammer();
    436 
    437   // Add occurence of event to our histogram, so that we can see what is being
    438   // done in a specific MessageLoop instance (i.e., specific thread).
    439   // If message_histogram_ is NULL, this is a no-op.
    440   void HistogramEvent(int event);
    441 
    442   // base::MessagePump::Delegate methods:
    443   virtual bool DoWork();
    444   virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time);
    445   virtual bool DoIdleWork();
    446 
    447   Type type_;
    448 
    449   // A list of tasks that need to be processed by this instance.  Note that
    450   // this queue is only accessed (push/pop) by our current thread.
    451   TaskQueue work_queue_;
    452 
    453   // Contains delayed tasks, sorted by their 'delayed_run_time' property.
    454   DelayedTaskQueue delayed_work_queue_;
    455 
    456   // A recent snapshot of Time::Now(), used to check delayed_work_queue_.
    457   base::TimeTicks recent_time_;
    458 
    459   // A queue of non-nestable tasks that we had to defer because when it came
    460   // time to execute them we were in a nested message loop.  They will execute
    461   // once we're out of nested message loops.
    462   TaskQueue deferred_non_nestable_work_queue_;
    463 
    464   scoped_refptr<base::MessagePump> pump_;
    465 
    466   ObserverList<DestructionObserver> destruction_observers_;
    467 
    468   // A recursion block that prevents accidentally running additonal tasks when
    469   // insider a (accidentally induced?) nested message pump.
    470   bool nestable_tasks_allowed_;
    471 
    472   bool exception_restoration_;
    473 
    474   std::string thread_name_;
    475   // A profiling histogram showing the counts of various messages and events.
    476   base::Histogram* message_histogram_;
    477 
    478   // A null terminated list which creates an incoming_queue of tasks that are
    479   // acquired under a mutex for processing on this instance's thread. These
    480   // tasks have not yet been sorted out into items for our work_queue_ vs
    481   // items that will be handled by the TimerManager.
    482   TaskQueue incoming_queue_;
    483   // Protect access to incoming_queue_.
    484   mutable base::Lock incoming_queue_lock_;
    485 
    486   RunState* state_;
    487 
    488 #if defined(OS_WIN)
    489   base::TimeTicks high_resolution_timer_expiration_;
    490   // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
    491   // which enter a modal message loop.
    492   bool os_modal_loop_;
    493 #endif
    494 
    495   // The next sequence number to use for delayed tasks.
    496   int next_sequence_num_;
    497 
    498   ObserverList<TaskObserver> task_observers_;
    499 
    500  private:
    501   DISALLOW_COPY_AND_ASSIGN(MessageLoop);
    502 };
    503 
    504 //-----------------------------------------------------------------------------
    505 // MessageLoopForUI extends MessageLoop with methods that are particular to a
    506 // MessageLoop instantiated with TYPE_UI.
    507 //
    508 // This class is typically used like so:
    509 //   MessageLoopForUI::current()->...call some method...
    510 //
    511 class BASE_API MessageLoopForUI : public MessageLoop {
    512  public:
    513   MessageLoopForUI() : MessageLoop(TYPE_UI) {
    514   }
    515 
    516   // Returns the MessageLoopForUI of the current thread.
    517   static MessageLoopForUI* current() {
    518     MessageLoop* loop = MessageLoop::current();
    519 #ifdef ANDROID
    520     DCHECK_EQ(static_cast<int>(MessageLoop::TYPE_UI),
    521               static_cast<int>(loop->type()));
    522 #else
    523     DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
    524 #endif
    525     return static_cast<MessageLoopForUI*>(loop);
    526   }
    527 
    528 #if defined(OS_WIN)
    529   void DidProcessMessage(const MSG& message);
    530 #endif  // defined(OS_WIN)
    531 
    532 #if defined(USE_X11)
    533   // Returns the Xlib Display that backs the MessagePump for this MessageLoop.
    534   //
    535   // This allows for raw access to the X11 server in situations where our
    536   // abstractions do not provide enough power.
    537   //
    538   // Be careful how this is used. The MessagePump in general expects
    539   // exclusive access to the Display. Calling things like XNextEvent() will
    540   // likely break things in subtle, hard to detect, ways.
    541   Display* GetDisplay();
    542 #endif  // defined(OS_X11)
    543 
    544 #if !defined(OS_MACOSX)
    545   // Please see message_pump_win/message_pump_glib for definitions of these
    546   // methods.
    547   void AddObserver(Observer* observer);
    548   void RemoveObserver(Observer* observer);
    549   void Run(Dispatcher* dispatcher);
    550 
    551  protected:
    552   // TODO(rvargas): Make this platform independent.
    553   base::MessagePumpForUI* pump_ui() {
    554     return static_cast<base::MessagePumpForUI*>(pump_.get());
    555   }
    556 #endif  // !defined(OS_MACOSX)
    557 };
    558 
    559 // Do not add any member variables to MessageLoopForUI!  This is important b/c
    560 // MessageLoopForUI is often allocated via MessageLoop(TYPE_UI).  Any extra
    561 // data that you need should be stored on the MessageLoop's pump_ instance.
    562 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
    563                MessageLoopForUI_should_not_have_extra_member_variables);
    564 
    565 //-----------------------------------------------------------------------------
    566 // MessageLoopForIO extends MessageLoop with methods that are particular to a
    567 // MessageLoop instantiated with TYPE_IO.
    568 //
    569 // This class is typically used like so:
    570 //   MessageLoopForIO::current()->...call some method...
    571 //
    572 class BASE_API MessageLoopForIO : public MessageLoop {
    573  public:
    574 #if defined(OS_WIN)
    575   typedef base::MessagePumpForIO::IOHandler IOHandler;
    576   typedef base::MessagePumpForIO::IOContext IOContext;
    577   typedef base::MessagePumpForIO::IOObserver IOObserver;
    578 #elif defined(OS_POSIX)
    579   typedef base::MessagePumpLibevent::Watcher Watcher;
    580   typedef base::MessagePumpLibevent::FileDescriptorWatcher
    581       FileDescriptorWatcher;
    582   typedef base::MessagePumpLibevent::IOObserver IOObserver;
    583 
    584   enum Mode {
    585     WATCH_READ = base::MessagePumpLibevent::WATCH_READ,
    586     WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE,
    587     WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE
    588   };
    589 
    590 #endif
    591 
    592   MessageLoopForIO() : MessageLoop(TYPE_IO) {
    593   }
    594 
    595   // Returns the MessageLoopForIO of the current thread.
    596   static MessageLoopForIO* current() {
    597     MessageLoop* loop = MessageLoop::current();
    598 #ifdef ANDROID
    599     DCHECK_EQ(static_cast<int>(MessageLoop::TYPE_IO),
    600               static_cast<int>(loop->type()));
    601 #else
    602     DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
    603 #endif
    604     return static_cast<MessageLoopForIO*>(loop);
    605   }
    606 
    607   void AddIOObserver(IOObserver* io_observer) {
    608     pump_io()->AddIOObserver(io_observer);
    609   }
    610 
    611   void RemoveIOObserver(IOObserver* io_observer) {
    612     pump_io()->RemoveIOObserver(io_observer);
    613   }
    614 
    615 #if defined(OS_WIN)
    616   // Please see MessagePumpWin for definitions of these methods.
    617   void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
    618   bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
    619 
    620  protected:
    621   // TODO(rvargas): Make this platform independent.
    622   base::MessagePumpForIO* pump_io() {
    623     return static_cast<base::MessagePumpForIO*>(pump_.get());
    624   }
    625 
    626 #elif defined(OS_POSIX)
    627   // Please see MessagePumpLibevent for definition.
    628   bool WatchFileDescriptor(int fd,
    629                            bool persistent,
    630                            Mode mode,
    631                            FileDescriptorWatcher *controller,
    632                            Watcher *delegate);
    633 
    634  private:
    635   base::MessagePumpLibevent* pump_io() {
    636     return static_cast<base::MessagePumpLibevent*>(pump_.get());
    637   }
    638 #endif  // defined(OS_POSIX)
    639 };
    640 
    641 // Do not add any member variables to MessageLoopForIO!  This is important b/c
    642 // MessageLoopForIO is often allocated via MessageLoop(TYPE_IO).  Any extra
    643 // data that you need should be stored on the MessageLoop's pump_ instance.
    644 COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
    645                MessageLoopForIO_should_not_have_extra_member_variables);
    646 
    647 #endif  // BASE_MESSAGE_LOOP_H_
    648