• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
remaining_delayNextWorkInfo48       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.
is_immediateNextWorkInfo55       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:
ScopedDoWorkItem()97       ScopedDoWorkItem() : outer_(nullptr), work_item_depth_(0) {}
98 
~ScopedDoWorkItem()99       ~ScopedDoWorkItem() {
100         if (outer_) {
101           outer_->OnEndWorkItem(work_item_depth_);
102         }
103       }
104 
ScopedDoWorkItem(ScopedDoWorkItem && rhs)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 
IsNull()123       bool IsNull() { return !outer_; }
124 
125      private:
126       friend Delegate;
127 
ScopedDoWorkItem(Delegate * outer)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.
BeginWorkItem()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     // May be called when starting to process native work and it is guaranteed
158     // that DoWork() will be called again before sleeping. Allows the delegate
159     // to skip unnecessary ScheduleWork() calls.
160     virtual void BeginNativeWorkBeforeDoWork() = 0;
161 
162     // Returns the nesting level at which the Delegate is currently running.
163     virtual int RunDepth() = 0;
164 
165    private:
166     // Called upon entering/exiting a ScopedDoWorkItem.
167     virtual void OnBeginWorkItem() = 0;
168     virtual void OnEndWorkItem(int work_item_depth) = 0;
169   };
170 
171   MessagePump();
172   virtual ~MessagePump();
173 
174   // The Run method is called to enter the message pump's run loop.
175   //
176   // Within the method, the message pump is responsible for processing native
177   // messages as well as for giving cycles to the delegate periodically. The
178   // message pump should take care to mix delegate callbacks with native message
179   // processing so neither type of event starves the other of cycles. Each call
180   // to a delegate function is considered the beginning of a new "unit of work".
181   //
182   // The anatomy of a typical run loop:
183   //
184   //   for (;;) {
185   //     bool did_native_work = false;
186   //     {
187   //       auto scoped_do_work_item = state_->delegate->BeginWorkItem();
188   //       did_native_work = DoNativeWork();
189   //     }
190   //     if (should_quit_)
191   //       break;
192   //
193   //     Delegate::NextWorkInfo next_work_info = delegate->DoWork();
194   //     if (should_quit_)
195   //       break;
196   //
197   //     if (did_native_work || next_work_info.is_immediate())
198   //       continue;
199   //
200   //     bool did_idle_work = delegate_->DoIdleWork();
201   //     if (should_quit_)
202   //       break;
203   //
204   //     if (did_idle_work)
205   //       continue;
206   //
207   //     WaitForWork();
208   //   }
209   //
210 
211   // Here, DoNativeWork is some private method of the message pump that is
212   // responsible for dispatching the next UI message or notifying the next IO
213   // completion (for example).  WaitForWork is a private method that simply
214   // blocks until there is more work of any type to do.
215   //
216   // Notice that the run loop cycles between calling DoNativeWork and DoWork
217   // methods. This helps ensure that none of these work queues starve the
218   // others. This is important for message pumps that are used to drive
219   // animations, for example.
220   //
221   // Notice also that after each callout to foreign code, the run loop checks to
222   // see if it should quit.  The Quit method is responsible for setting this
223   // flag.  No further work is done once the quit flag is set.
224   //
225   // NOTE 1: Run may be called reentrantly from any of the callouts to foreign
226   // code (internal work, DoWork, DoIdleWork). As a result, DoWork and
227   // DoIdleWork must be reentrant.
228   //
229   // NOTE 2: Run implementations must arrange for DoWork to be invoked as
230   // expected if a callout to foreign code enters a message pump outside their
231   // control. For example, the MessageBox API on Windows pumps UI messages. If
232   // the MessageBox API is called (indirectly) from within Run, it is expected
233   // that DoWork will be invoked from within that call in response to
234   // ScheduleWork or as requested by the last NextWorkInfo returned by DoWork.
235   // The MessagePump::Delegate may then elect to do nested work or not depending
236   // on its policy in that context. Regardless of that decision (and return
237   // value of the nested DoWork() call), DoWork() will be invoked again when the
238   // nested loop unwinds.
239   virtual void Run(Delegate* delegate) = 0;
240 
241   // Quit immediately from the most recently entered run loop.  This method may
242   // only be used on the thread that called Run.
243   virtual void Quit() = 0;
244 
245   // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a
246   // DoWork callback is already scheduled. Once this call is made, DoWork is
247   // guaranteed to be called repeatedly at least until it returns a
248   // non-immediate NextWorkInfo. This call can be expensive and callers should
249   // attempt not to invoke it again before a non-immediate NextWorkInfo was
250   // returned from DoWork(). Thread-safe (and callers should avoid holding a
251   // Lock at all cost while making this call as some platforms' priority
252   // boosting features have been observed to cause the caller to get descheduled
253   // : https://crbug.com/890978).
254   virtual void ScheduleWork() = 0;
255 
256   // Schedule a DoWork callback to happen at the specified time, cancelling any
257   // pending callback scheduled by this method. This method may only be used on
258   // the thread that called Run.
259   //
260   // It isn't necessary to call this during normal execution, as the pump wakes
261   // up as requested by the return value of DoWork().
262   // TODO(crbug.com/885371): Determine if this must be called to ensure that
263   // delayed tasks run when a message pump outside the control of Run is
264   // entered.
265   virtual void ScheduleDelayedWork(
266       const Delegate::NextWorkInfo& next_work_info) = 0;
267 
268   // Returns an adjusted |run_time| based on alignment policies of the pump.
269   virtual TimeTicks AdjustDelayedRunTime(TimeTicks earliest_time,
270                                          TimeTicks run_time,
271                                          TimeTicks latest_time);
272 };
273 
274 }  // namespace base
275 
276 #endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
277