tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

message_pump.h (11003B)


      1 // Copyright 2012 The Chromium Authors
      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_MESSAGE_PUMP_H_
      6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
      7 
      8 #include <memory>
      9 #include <utility>
     10 
     11 #include "base/base_export.h"
     12 #include "base/check.h"
     13 #include "base/check_op.h"
     14 #include "base/memory/raw_ptr_exclusion.h"
     15 #include "base/message_loop/message_pump_type.h"
     16 #include "base/sequence_checker.h"
     17 #include "base/time/time.h"
     18 #include "build/build_config.h"
     19 
     20 namespace base {
     21 
     22 class TimeTicks;
     23 
     24 class BASE_EXPORT MessagePump {
     25 public:
     26  using MessagePumpFactory = std::unique_ptr<MessagePump>();
     27  // Uses the given base::MessagePumpFactory to override the default MessagePump
     28  // implementation for 'MessagePumpType::UI'. May only be called once.
     29  static void OverrideMessagePumpForUIFactory(MessagePumpFactory* factory);
     30 
     31  // Returns true if the MessagePumpForUI has been overidden.
     32  static bool IsMessagePumpForUIFactoryOveridden();
     33 
     34  static void InitializeFeatures();
     35 
     36  // Creates the default MessagePump based on |type|. Caller owns return value.
     37  static std::unique_ptr<MessagePump> Create(MessagePumpType type);
     38 
     39  // Please see the comments above the Run method for an illustration of how
     40  // these delegate methods are used.
     41  class BASE_EXPORT Delegate {
     42   public:
     43    virtual ~Delegate() = default;
     44 
     45    struct NextWorkInfo {
     46      // Helper to extract a TimeDelta for pumps that need a
     47      // timeout-till-next-task.
     48      TimeDelta remaining_delay() const {
     49        DCHECK(!delayed_run_time.is_null() && !delayed_run_time.is_max());
     50        DCHECK_GE(TimeTicks::Now(), recent_now);
     51        return delayed_run_time - recent_now;
     52      }
     53 
     54      // Helper to verify if the next task is ready right away.
     55      bool is_immediate() const { return delayed_run_time.is_null(); }
     56 
     57      // The next PendingTask's |delayed_run_time|. is_null() if there's extra
     58      // work to run immediately. is_max() if there are no more immediate nor
     59      // delayed tasks.
     60      TimeTicks delayed_run_time;
     61 
     62      // |leeway| determines the preferred time range for scheduling
     63      // work. A larger leeway provides more freedom to schedule work at
     64      // an optimal time for power consumption. This field is ignored
     65      // for immediate work.
     66      TimeDelta leeway;
     67 
     68      // A recent view of TimeTicks::Now(). Only valid if |delayed_run_time|
     69      // isn't null nor max. MessagePump impls should use remaining_delay()
     70      // instead of resampling Now() if they wish to sleep for a TimeDelta.
     71      TimeTicks recent_now;
     72 
     73      // If true, native messages should be processed before executing more work
     74      // from the Delegate. This is an optional hint; not all message pumps
     75      // implement this.
     76      bool yield_to_native = false;
     77    };
     78 
     79    // Executes an immediate task or a ripe delayed task. Returns information
     80    // about when DoWork() should be called again. If the returned NextWorkInfo
     81    // is_immediate(), DoWork() must be invoked again shortly. Else, DoWork()
     82    // must be invoked at |NextWorkInfo::delayed_run_time| or when
     83    // ScheduleWork() is invoked, whichever comes first. Redundant/spurious
     84    // invocations of DoWork() outside of those requirements are tolerated.
     85    // DoIdleWork() will not be called so long as this returns a NextWorkInfo
     86    // which is_immediate().
     87    virtual NextWorkInfo DoWork() = 0;
     88 
     89    // Called from within Run just before the message pump goes to sleep.
     90    // Returns true to indicate that idle work was done; in which case Run()
     91    // should resume with calling DoWork(). Returning false means the pump
     92    // should now wait.
     93    virtual bool DoIdleWork() = 0;
     94 
     95    class ScopedDoWorkItem {
     96     public:
     97      ScopedDoWorkItem() : outer_(nullptr), work_item_depth_(0) {}
     98 
     99      ~ScopedDoWorkItem() {
    100        if (outer_) {
    101          outer_->OnEndWorkItem(work_item_depth_);
    102        }
    103      }
    104 
    105      ScopedDoWorkItem(ScopedDoWorkItem&& rhs)
    106          : outer_(std::exchange(rhs.outer_, nullptr)),
    107            work_item_depth_(rhs.work_item_depth_) {}
    108      ScopedDoWorkItem& operator=(ScopedDoWorkItem&& rhs) {
    109        // We should only ever go from an empty ScopedDoWorkItem to an
    110        // initialized one, or from an initialized one to an empty one.
    111        CHECK_NE(IsNull(), rhs.IsNull());
    112        // Since we're overwriting this ScopedDoWorkItem, we need to record its
    113        // destruction.
    114        if (outer_) {
    115          outer_->OnEndWorkItem(work_item_depth_);
    116        }
    117 
    118        work_item_depth_ = rhs.work_item_depth_;
    119        outer_ = std::exchange(rhs.outer_, nullptr);
    120        return *this;
    121      }
    122 
    123      bool IsNull() { return !outer_; }
    124 
    125     private:
    126      friend Delegate;
    127 
    128      explicit ScopedDoWorkItem(Delegate* outer) : outer_(outer) {
    129        outer_->OnBeginWorkItem();
    130        work_item_depth_ = outer_->RunDepth();
    131      }
    132 
    133      // `outer_` is not a raw_ptr<...> for performance reasons (based on
    134      // analysis of sampling profiler data and tab_search:top100:2020).
    135      RAW_PTR_EXCLUSION Delegate* outer_;
    136 
    137      // Records the run level at which this DoWorkItem was created to allow
    138      // detection of exits of nested loops.
    139      int work_item_depth_;
    140    };
    141 
    142    // Called before a unit of work is executed. This allows reports
    143    // about individual units of work to be produced. The unit of work ends when
    144    // the returned ScopedDoWorkItem goes out of scope.
    145    // TODO(crbug.com/851163): Place calls for all platforms. Without this, some
    146    // state like the top-level "ThreadController active" trace event will not
    147    // be correct when work is performed.
    148    [[nodiscard]] ScopedDoWorkItem BeginWorkItem() {
    149      return ScopedDoWorkItem(this);
    150    }
    151 
    152    // Called before the message pump starts waiting for work. This indicates
    153    // that the message pump is idle (out of application work and ideally out of
    154    // native work -- if it can tell).
    155    virtual void BeforeWait() = 0;
    156 
    157    // Returns the nesting level at which the Delegate is currently running.
    158    virtual int RunDepth() = 0;
    159 
    160   private:
    161    // Called upon entering/exiting a ScopedDoWorkItem.
    162    virtual void OnBeginWorkItem() = 0;
    163    virtual void OnEndWorkItem(int work_item_depth) = 0;
    164  };
    165 
    166  MessagePump();
    167  virtual ~MessagePump();
    168 
    169  // The Run method is called to enter the message pump's run loop.
    170  //
    171  // Within the method, the message pump is responsible for processing native
    172  // messages as well as for giving cycles to the delegate periodically. The
    173  // message pump should take care to mix delegate callbacks with native message
    174  // processing so neither type of event starves the other of cycles. Each call
    175  // to a delegate function is considered the beginning of a new "unit of work".
    176  //
    177  // The anatomy of a typical run loop:
    178  //
    179  //   for (;;) {
    180  //     bool did_native_work = false;
    181  //     {
    182  //       auto scoped_do_work_item = state_->delegate->BeginWorkItem();
    183  //       did_native_work = DoNativeWork();
    184  //     }
    185  //     if (should_quit_)
    186  //       break;
    187  //
    188  //     Delegate::NextWorkInfo next_work_info = delegate->DoWork();
    189  //     if (should_quit_)
    190  //       break;
    191  //
    192  //     if (did_native_work || next_work_info.is_immediate())
    193  //       continue;
    194  //
    195  //     bool did_idle_work = delegate_->DoIdleWork();
    196  //     if (should_quit_)
    197  //       break;
    198  //
    199  //     if (did_idle_work)
    200  //       continue;
    201  //
    202  //     WaitForWork();
    203  //   }
    204  //
    205 
    206  // Here, DoNativeWork is some private method of the message pump that is
    207  // responsible for dispatching the next UI message or notifying the next IO
    208  // completion (for example).  WaitForWork is a private method that simply
    209  // blocks until there is more work of any type to do.
    210  //
    211  // Notice that the run loop cycles between calling DoNativeWork and DoWork
    212  // methods. This helps ensure that none of these work queues starve the
    213  // others. This is important for message pumps that are used to drive
    214  // animations, for example.
    215  //
    216  // Notice also that after each callout to foreign code, the run loop checks to
    217  // see if it should quit.  The Quit method is responsible for setting this
    218  // flag.  No further work is done once the quit flag is set.
    219  //
    220  // NOTE 1: Run may be called reentrantly from any of the callouts to foreign
    221  // code (internal work, DoWork, DoIdleWork). As a result, DoWork and
    222  // DoIdleWork must be reentrant.
    223  //
    224  // NOTE 2: Run implementations must arrange for DoWork to be invoked as
    225  // expected if a callout to foreign code enters a message pump outside their
    226  // control. For example, the MessageBox API on Windows pumps UI messages. If
    227  // the MessageBox API is called (indirectly) from within Run, it is expected
    228  // that DoWork will be invoked from within that call in response to
    229  // ScheduleWork or as requested by the last NextWorkInfo returned by DoWork.
    230  // The MessagePump::Delegate may then elect to do nested work or not depending
    231  // on its policy in that context. Regardless of that decision (and return
    232  // value of the nested DoWork() call), DoWork() will be invoked again when the
    233  // nested loop unwinds.
    234  virtual void Run(Delegate* delegate) = 0;
    235 
    236  // Quit immediately from the most recently entered run loop.  This method may
    237  // only be used on the thread that called Run.
    238  virtual void Quit() = 0;
    239 
    240  // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a
    241  // DoWork callback is already scheduled. Once this call is made, DoWork is
    242  // guaranteed to be called repeatedly at least until it returns a
    243  // non-immediate NextWorkInfo. This call can be expensive and callers should
    244  // attempt not to invoke it again before a non-immediate NextWorkInfo was
    245  // returned from DoWork(). Thread-safe (and callers should avoid holding a
    246  // Lock at all cost while making this call as some platforms' priority
    247  // boosting features have been observed to cause the caller to get descheduled
    248  // : https://crbug.com/890978).
    249  virtual void ScheduleWork() = 0;
    250 
    251  // Schedule a DoWork callback to happen at the specified time, cancelling any
    252  // pending callback scheduled by this method. This method may only be used on
    253  // the thread that called Run.
    254  //
    255  // It isn't necessary to call this during normal execution, as the pump wakes
    256  // up as requested by the return value of DoWork().
    257  // TODO(crbug.com/885371): Determine if this must be called to ensure that
    258  // delayed tasks run when a message pump outside the control of Run is
    259  // entered.
    260  virtual void ScheduleDelayedWork(
    261      const Delegate::NextWorkInfo& next_work_info) = 0;
    262 
    263  // Returns an adjusted |run_time| based on alignment policies of the pump.
    264  virtual TimeTicks AdjustDelayedRunTime(TimeTicks earliest_time,
    265                                         TimeTicks run_time,
    266                                         TimeTicks latest_time);
    267 };
    268 
    269 }  // namespace base
    270 
    271 #endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_