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