DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (4b332005f925)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MESSAGE_PUMP_H_
#define BASE_MESSAGE_PUMP_H_

#include "nsISupportsImpl.h"

class nsIEventTarget;

namespace base {

class TimeTicks;

class MessagePump {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MessagePump)

  // Please see the comments above the Run method for an illustration of how
  // these delegate methods are used.
  class Delegate {
   public:
    virtual ~Delegate() {}

    // Called from within Run in response to ScheduleWork or when the message
    // pump would otherwise call DoDelayedWork.  Returns true to indicate that
    // work was done.  DoDelayedWork will not be called if DoWork returns true.
    virtual bool DoWork() = 0;

    // Called from within Run in response to ScheduleDelayedWork or when the
    // message pump would otherwise sleep waiting for more work.  Returns true
    // to indicate that delayed work was done.  DoIdleWork will not be called
    // if DoDelayedWork returns true.  Upon return |next_delayed_work_time|
    // indicates the time when DoDelayedWork should be called again.  If
    // |next_delayed_work_time| is null (per Time::is_null), then the queue of
    // future delayed work (timer events) is currently empty, and no additional
    // calls to this function need to be scheduled.
    virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;

    // Called from within Run just before the message pump goes to sleep.
    // Returns true to indicate that idle work was done.
    virtual bool DoIdleWork() = 0;
  };

  // The Run method is called to enter the message pump's run loop.
  //
  // Within the method, the message pump is responsible for processing native
  // messages as well as for giving cycles to the delegate periodically.  The
  // message pump should take care to mix delegate callbacks with native
  // message processing so neither type of event starves the other of cycles.
  //
  // The anatomy of a typical run loop:
  //
  //   for (;;) {
  //     bool did_work = DoInternalWork();
  //     if (should_quit_)
  //       break;
  //
  //     did_work |= delegate_->DoWork();
  //     if (should_quit_)
  //       break;
  //
  //     did_work |= delegate_->DoDelayedWork();
  //     if (should_quit_)
  //       break;
  //
  //     if (did_work)
  //       continue;
  //
  //     did_work = delegate_->DoIdleWork();
  //     if (should_quit_)
  //       break;
  //
  //     if (did_work)
  //       continue;
  //
  //     WaitForWork();
  //   }
  //
  // Here, DoInternalWork is some private method of the message pump that is
  // responsible for dispatching the next UI message or notifying the next IO
  // completion (for example).  WaitForWork is a private method that simply
  // blocks until there is more work of any type to do.
  //
  // Notice that the run loop cycles between calling DoInternalWork, DoWork,
  // and DoDelayedWork methods.  This helps ensure that neither work queue
  // starves the other.  This is important for message pumps that are used to
  // drive animations, for example.
  //
  // Notice also that after each callout to foreign code, the run loop checks
  // to see if it should quit.  The Quit method is responsible for setting this
  // flag.  No further work is done once the quit flag is set.
  //
  // NOTE: Care must be taken to handle Run being called again from within any
  // of the callouts to foreign code.  Native message pumps may also need to
  // deal with other native message pumps being run outside their control
  // (e.g., the MessageBox API on Windows pumps UI messages!).  To be specific,
  // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
  // nested sub-loops that are "seemingly" outside the control of this message
  // pump.  DoWork in particular must never be starved for time slices unless
  // it returns false (meaning it has run out of things to do).
  //
  virtual void Run(Delegate* delegate) = 0;

  // Quit immediately from the most recently entered run loop.  This method may
  // only be used on the thread that called Run.
  virtual void Quit() = 0;

  // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a
  // DoWork callback is already scheduled.  This method may be called from any
  // thread.  Once this call is made, DoWork should not be "starved" at least
  // until it returns a value of false.
  virtual void ScheduleWork() = 0;

  // This method may only called from the thread that called Run.
  //
  // Ensure that DoWork will be called if a nested loop is entered.
  // If a MessagePump can already guarantee that DoWork will be called
  // "reasonably soon", this method can be a no-op to avoid expensive
  // atomic tests and/or syscalls required for ScheduleWork().
  virtual void ScheduleWorkForNestedLoop() { ScheduleWork(); };

  // Schedule a DoDelayedWork callback to happen at the specified time,
  // cancelling any pending DoDelayedWork callback.  This method may only be
  // used on the thread that called Run.
  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;

  // If returned, just use the nsThread.
  virtual nsIEventTarget* GetXPCOMThread() { return nullptr; }

 protected:
  virtual ~MessagePump(){};
};

}  // namespace base

#endif  // BASE_MESSAGE_PUMP_H_