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
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298

base / message_loop / message_pump.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_

#include <memory>
#include <utility>

#include "base/base_export.h"
#include "base/check.h"
#include "base/check_op.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/message_loop/message_pump_type.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/build_config.h"

namespace base {

class IOWatcher;
class TimeTicks;

class BASE_EXPORT MessagePump {
 public:
  using MessagePumpFactory = std::unique_ptr<MessagePump>();
  // Uses the given base::MessagePumpFactory to override the default MessagePump
  // implementation for 'MessagePumpType::UI'. May only be called once.
  static void OverrideMessagePumpForUIFactory(MessagePumpFactory* factory);

  // Returns true if the MessagePumpForUI has been overidden.
  static bool IsMessagePumpForUIFactoryOveridden();

  static void InitializeFeatures();

  // Manage the state of |kAlignWakeUps| and the leeway of the process.
  static void OverrideAlignWakeUpsState(bool enabled, TimeDelta leeway);
  static void ResetAlignWakeUpsState();
  static bool GetAlignWakeUpsEnabled();
  static TimeDelta GetLeewayIgnoringThreadOverride();
  static TimeDelta GetLeewayForCurrentThread();

  // Creates the default MessagePump based on |type|. Caller owns return value.
  static std::unique_ptr<MessagePump> Create(MessagePumpType type);

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

    struct NextWorkInfo {
      // Helper to extract a TimeDelta for pumps that need a
      // timeout-till-next-task.
      TimeDelta remaining_delay() const {
        DCHECK(!delayed_run_time.is_null() && !delayed_run_time.is_max());
        DCHECK_GE(TimeTicks::Now(), recent_now);
        return delayed_run_time - recent_now;
      }

      // Helper to verify if the next task is ready right away.
      bool is_immediate() const { return delayed_run_time.is_null(); }

      // The next PendingTask's |delayed_run_time|. is_null() if there's extra
      // work to run immediately. is_max() if there are no more immediate nor
      // delayed tasks.
      TimeTicks delayed_run_time;

      // |leeway| determines the preferred time range for scheduling
      // work. A larger leeway provides more freedom to schedule work at
      // an optimal time for power consumption. This field is ignored
      // for immediate work.
      TimeDelta leeway;

      // A recent view of TimeTicks::Now(). Only valid if |delayed_run_time|
      // isn't null nor max. MessagePump impls should use remaining_delay()
      // instead of resampling Now() if they wish to sleep for a TimeDelta.
      TimeTicks recent_now;

      // If true, native messages should be processed before executing more work
      // from the Delegate. This is an optional hint; not all message pumps
      // implement this.
      bool yield_to_native = false;
    };

    // Executes an immediate task or a ripe delayed task. Returns information
    // about when DoWork() should be called again. If the returned NextWorkInfo
    // is_immediate(), DoWork() must be invoked again shortly. Else, DoWork()
    // must be invoked at |NextWorkInfo::delayed_run_time| or when
    // ScheduleWork() is invoked, whichever comes first. Redundant/spurious
    // invocations of DoWork() outside of those requirements are tolerated.
    // DoIdleWork() will not be called so long as this returns a NextWorkInfo
    // which is_immediate().
    virtual NextWorkInfo DoWork() = 0;

    // Called from within Run just before the message pump goes to sleep.
    virtual void DoIdleWork() = 0;

    class ScopedDoWorkItem {
     public:
      ScopedDoWorkItem() : outer_(nullptr), work_item_depth_(0) {}

      ~ScopedDoWorkItem() {
        if (outer_) {
          outer_->OnEndWorkItem(work_item_depth_);
        }
      }

      ScopedDoWorkItem(ScopedDoWorkItem&& rhs)
          : outer_(std::exchange(rhs.outer_, nullptr)),
            work_item_depth_(rhs.work_item_depth_) {}
      ScopedDoWorkItem& operator=(ScopedDoWorkItem&& rhs) {
        // We should only ever go from an empty ScopedDoWorkItem to an
        // initialized one, or from an initialized one to an empty one.
        CHECK_NE(IsNull(), rhs.IsNull());
        // Since we're overwriting this ScopedDoWorkItem, we need to record its
        // destruction.
        if (outer_) {
          outer_->OnEndWorkItem(work_item_depth_);
        }

        work_item_depth_ = rhs.work_item_depth_;
        outer_ = std::exchange(rhs.outer_, nullptr);
        return *this;
      }

      bool IsNull() { return !outer_; }

     private:
      friend Delegate;

      explicit ScopedDoWorkItem(Delegate* outer) : outer_(outer) {
        outer_->OnBeginWorkItem();
        work_item_depth_ = outer_->RunDepth();
      }

      // `outer_` is not a raw_ptr<...> for performance reasons (based on
      // analysis of sampling profiler data and tab_search:top100:2020).
      RAW_PTR_EXCLUSION Delegate* outer_;

      // Records the run level at which this DoWorkItem was created to allow
      // detection of exits of nested loops.
      int work_item_depth_;
    };

    // Called before a unit of work is executed. This allows reports
    // about individual units of work to be produced. The unit of work ends when
    // the returned ScopedDoWorkItem goes out of scope.
    // TODO(crbug.com/40580088): Place calls for all platforms. Without this,
    // some state like the top-level "ThreadController active" trace event will
    // not be correct when work is performed.
    [[nodiscard]] ScopedDoWorkItem BeginWorkItem() {
      return ScopedDoWorkItem(this);
    }

    // Called before the message pump starts waiting for work. This indicates
    // that the message pump is idle (out of application work and ideally out of
    // native work -- if it can tell).
    virtual void BeforeWait() = 0;

    // May be called when starting to process native work and it is guaranteed
    // that DoWork() will be called again before sleeping. Allows the delegate
    // to skip unnecessary ScheduleWork() calls.
    virtual void BeginNativeWorkBeforeDoWork() = 0;

    // Returns the nesting level at which the Delegate is currently running.
    virtual int RunDepth() = 0;

   private:
    // Called upon entering/exiting a ScopedDoWorkItem.
    virtual void OnBeginWorkItem() = 0;
    virtual void OnEndWorkItem(int work_item_depth) = 0;
  };

  MessagePump();
  virtual ~MessagePump();

  // 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. Each call
  // to a delegate function is considered the beginning of a new "unit of work".
  //
  // The anatomy of a typical run loop:
  //
  //   for (;;) {
  //     bool did_native_work = false;
  //     {
  //       auto scoped_do_work_item = state_->delegate->BeginWorkItem();
  //       did_native_work = DoNativeWork();
  //     }
  //     if (should_quit_)
  //       break;
  //
  //     Delegate::NextWorkInfo next_work_info = delegate->DoWork();
  //     if (should_quit_)
  //       break;
  //
  //     if (did_native_work || next_work_info.is_immediate())
  //       continue;
  //
  //     delegate_->DoIdleWork();
  //     if (should_quit_)
  //       break;
  //
  //     if (did_idle_work)
  //       continue;
  //
  //     WaitForWork();
  //   }
  //

  // Here, DoNativeWork 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 DoNativeWork and DoWork
  // methods. This helps ensure that none of these work queues starve the
  // others. 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 1: Run may be called reentrantly from any of the callouts to foreign
  // code (internal work, DoWork, DoIdleWork). As a result, DoWork and
  // DoIdleWork must be reentrant.
  //
  // NOTE 2: Run implementations must arrange for DoWork to be invoked as
  // expected if a callout to foreign code enters a message pump outside their
  // control. For example, the MessageBox API on Windows pumps UI messages. If
  // the MessageBox API is called (indirectly) from within Run, it is expected
  // that DoWork will be invoked from within that call in response to
  // ScheduleWork or as requested by the last NextWorkInfo returned by DoWork.
  // The MessagePump::Delegate may then elect to do nested work or not depending
  // on its policy in that context. Regardless of that decision (and return
  // value of the nested DoWork() call), DoWork() will be invoked again when the
  // nested loop unwinds.
  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. Once this call is made, DoWork is
  // guaranteed to be called repeatedly at least until it returns a
  // non-immediate NextWorkInfo. This call can be expensive and callers should
  // attempt not to invoke it again before a non-immediate NextWorkInfo was
  // returned from DoWork(). Thread-safe (and callers should avoid holding a
  // Lock at all cost while making this call as some platforms' priority
  // boosting features have been observed to cause the caller to get descheduled
  // : https://crbug.com/890978).
  virtual void ScheduleWork() = 0;

  // Schedule a DoWork callback to happen at the specified time, cancelling any
  // pending callback scheduled by this method. This method may only be used on
  // the thread that called Run.
  //
  // It isn't necessary to call this during normal execution, as the pump wakes
  // up as requested by the return value of DoWork().
  // TODO(crbug.com/40594269): Determine if this must be called to ensure that
  // delayed tasks run when a message pump outside the control of Run is
  // entered.
  virtual void ScheduleDelayedWork(
      const Delegate::NextWorkInfo& next_work_info) = 0;

  // Returns an adjusted |run_time| based on alignment policies of the pump.
  virtual TimeTicks AdjustDelayedRunTime(TimeTicks earliest_time,
                                         TimeTicks run_time,
                                         TimeTicks latest_time);

  // Requests the pump to handle either the likely imminent creation (`true`) or
  // destruction (`false`) of a native nested loop in which application tasks
  // are desired to be run. The pump should override and return `true` if it
  // supports this call and has scheduled work in response. The default
  // implementation returns `false` and does nothing.
  virtual bool HandleNestedNativeLoopWithApplicationTasks(
      bool application_tasks_desired);

  // If the MessagePump implementation supports async IO event handling, this
  // returns a valid IOWatcher implementation to use. Otherwise returns null.
  virtual IOWatcher* GetIOWatcher();

 private:
  // TODO(crbug.com/379190028): Individual MessagePump subclasses should own and
  // initialize their own IOWatcher.
  std::unique_ptr<IOWatcher> io_watcher_;
};

}  // namespace base

#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_