[email protected] | f2ebbf06 | 2012-04-06 03:14:30 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 4 | |
[email protected] | 59e69e74 | 2013-06-18 20:27:52 | [diff] [blame] | 5 | #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ |
| 6 | #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 7 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 8 | #include "base/base_export.h" |
Hans Wennborg | 7b53371 | 2020-06-22 20:52:27 | [diff] [blame] | 9 | #include "base/check_op.h" |
Carlos Caballero | d70e603 | 2019-07-30 12:27:27 | [diff] [blame] | 10 | #include "base/message_loop/message_pump_type.h" |
[email protected] | 57cd3d2 | 2014-06-05 19:36:20 | [diff] [blame] | 11 | #include "base/message_loop/timer_slack.h" |
gab | 7d2fae4 | 2017-06-01 14:02:55 | [diff] [blame] | 12 | #include "base/sequence_checker.h" |
Gabriel Charette | 06c3497 | 2019-02-04 18:38:35 | [diff] [blame] | 13 | #include "base/time/time.h" |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 14 | #include "build/build_config.h" |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 15 | |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 16 | namespace base { |
| 17 | |
[email protected] | 7e7fab4 | 2010-11-06 22:23:29 | [diff] [blame] | 18 | class TimeTicks; |
[email protected] | e1acf6f | 2008-10-27 20:43:33 | [diff] [blame] | 19 | |
gab | 7d2fae4 | 2017-06-01 14:02:55 | [diff] [blame] | 20 | class BASE_EXPORT MessagePump { |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 21 | public: |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 22 | using MessagePumpFactory = std::unique_ptr<MessagePump>(); |
| 23 | // Uses the given base::MessagePumpFactory to override the default MessagePump |
Carlos Caballero | b2e5b6d8 | 2019-09-04 09:04:39 | [diff] [blame] | 24 | // implementation for 'MessagePumpType::UI'. May only be called once. |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 25 | static void OverrideMessagePumpForUIFactory(MessagePumpFactory* factory); |
| 26 | |
| 27 | // Returns true if the MessagePumpForUI has been overidden. |
| 28 | static bool IsMessagePumpForUIFactoryOveridden(); |
| 29 | |
| 30 | // Creates the default MessagePump based on |type|. Caller owns return value. |
Carlos Caballero | d70e603 | 2019-07-30 12:27:27 | [diff] [blame] | 31 | static std::unique_ptr<MessagePump> Create(MessagePumpType type); |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 32 | |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 33 | // Please see the comments above the Run method for an illustration of how |
| 34 | // these delegate methods are used. |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 35 | class BASE_EXPORT Delegate { |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 36 | public: |
Chris Watkins | 091d629 | 2017-12-13 04:25:58 | [diff] [blame] | 37 | virtual ~Delegate() = default; |
[email protected] | b16ef31 | 2008-08-19 18:36:23 | [diff] [blame] | 38 | |
Olivier Li | 26dede5 | 2020-02-27 19:33:59 | [diff] [blame] | 39 | // Called before a unit of work internal to the message pump is executed. |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 40 | // This allows reports about individual units of work to be produced. The |
| 41 | // unit of work ends when BeforeDoInternalWork() is called again, or when |
| 42 | // BeforeWait(), DoWork(), or DoIdleWork() is called. |
Olivier Li | 26dede5 | 2020-02-27 19:33:59 | [diff] [blame] | 43 | // TODO(crbug.com/851163): Place calls for all platforms. |
Mike Wittman | 45a9b6b | 2019-02-06 18:06:21 | [diff] [blame] | 44 | virtual void BeforeDoInternalWork() = 0; |
Mike Wittman | cb1067c | 2019-01-24 19:04:00 | [diff] [blame] | 45 | |
Olivier Li | 26dede5 | 2020-02-27 19:33:59 | [diff] [blame] | 46 | // Called before the message pump starts waiting for work. |
| 47 | // This indicates the end of the current unit of work, which is required |
| 48 | // to produce reports about individual units of work. |
| 49 | virtual void BeforeWait() = 0; |
| 50 | |
Gabriel Charette | 06c3497 | 2019-02-04 18:38:35 | [diff] [blame] | 51 | struct NextWorkInfo { |
| 52 | // Helper to extract a TimeDelta for pumps that need a |
| 53 | // timeout-till-next-task. |
| 54 | TimeDelta remaining_delay() const { |
| 55 | DCHECK(!delayed_run_time.is_null() && !delayed_run_time.is_max()); |
| 56 | DCHECK_GE(TimeTicks::Now(), recent_now); |
| 57 | return delayed_run_time - recent_now; |
| 58 | } |
| 59 | |
| 60 | // Helper to verify if the next task is ready right away. |
| 61 | bool is_immediate() const { return delayed_run_time.is_null(); } |
| 62 | |
| 63 | // The next PendingTask's |delayed_run_time|. is_null() if there's extra |
| 64 | // work to run immediately. is_max() if there are no more immediate nor |
| 65 | // delayed tasks. |
| 66 | TimeTicks delayed_run_time; |
| 67 | |
| 68 | // A recent view of TimeTicks::Now(). Only valid if |next_task_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 | |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 74 | // Executes an immediate task or a ripe delayed task. Returns information |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 75 | // about when DoWork() should be called again. If the returned NextWorkInfo |
| 76 | // is_immediate(), DoWork() must be invoked again shortly. Else, DoWork() |
| 77 | // must be invoked at |NextWorkInfo::delayed_run_time| or when |
| 78 | // ScheduleWork() is invoked, whichever comes first. Redundant/spurious |
| 79 | // invocations of DoWork() outside of those requirements are tolerated. |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 80 | // DoIdleWork() will not be called so long as this returns a NextWorkInfo |
| 81 | // which is_immediate(). |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 82 | virtual NextWorkInfo DoWork() = 0; |
Gabriel Charette | 06c3497 | 2019-02-04 18:38:35 | [diff] [blame] | 83 | |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 84 | // Called from within Run just before the message pump goes to sleep. |
cpu | ee890795 | 2014-08-28 23:25:37 | [diff] [blame] | 85 | // Returns true to indicate that idle work was done. Returning false means |
| 86 | // the pump will now wait. |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 87 | virtual bool DoIdleWork() = 0; |
| 88 | }; |
| 89 | |
[email protected] | d4799a3 | 2010-09-28 22:54:58 | [diff] [blame] | 90 | MessagePump(); |
[email protected] | 54aa4f1 | 2013-07-22 22:24:13 | [diff] [blame] | 91 | virtual ~MessagePump(); |
[email protected] | 52a261f | 2009-03-03 15:01:12 | [diff] [blame] | 92 | |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 93 | // The Run method is called to enter the message pump's run loop. |
| 94 | // |
| 95 | // Within the method, the message pump is responsible for processing native |
Olivier Li | 26dede5 | 2020-02-27 19:33:59 | [diff] [blame] | 96 | // messages as well as for giving cycles to the delegate periodically. The |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 97 | // message pump should take care to mix delegate callbacks with native message |
| 98 | // processing so neither type of event starves the other of cycles. Each call |
| 99 | // to a delegate function or DoInternalWork() is considered the beginning of a |
| 100 | // new "unit of work". |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 101 | // |
| 102 | // The anatomy of a typical run loop: |
| 103 | // |
| 104 | // for (;;) { |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 105 | // bool did_internal_work = DoInternalWork(); |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 106 | // if (should_quit_) |
| 107 | // break; |
[email protected] | 9bcbf47 | 2008-08-30 00:22:48 | [diff] [blame] | 108 | // |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 109 | // Delegate::NextWorkInfo next_work_info = delegate->DoWork(); |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 110 | // if (should_quit_) |
| 111 | // break; |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 112 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 113 | // if (did_internal_work || next_work_info.is_immediate()) |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 114 | // continue; |
| 115 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 116 | // bool did_idle_work = delegate_->DoIdleWork(); |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 117 | // if (should_quit_) |
| 118 | // break; |
[email protected] | 9bcbf47 | 2008-08-30 00:22:48 | [diff] [blame] | 119 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 120 | // if (did_idle_work) |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 121 | // continue; |
| 122 | // |
| 123 | // WaitForWork(); |
| 124 | // } |
| 125 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 126 | |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 127 | // Here, DoInternalWork is some private method of the message pump that is |
| 128 | // responsible for dispatching the next UI message or notifying the next IO |
| 129 | // completion (for example). WaitForWork is a private method that simply |
| 130 | // blocks until there is more work of any type to do. |
| 131 | // |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 132 | // Notice that the run loop cycles between calling DoInternalWork and DoWork |
| 133 | // methods. This helps ensure that none of these work queues starve the |
| 134 | // others. This is important for message pumps that are used to drive |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 135 | // animations, for example. |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 136 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 137 | // Notice also that after each callout to foreign code, the run loop checks to |
| 138 | // see if it should quit. The Quit method is responsible for setting this |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 139 | // flag. No further work is done once the quit flag is set. |
| 140 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 141 | // NOTE 1: Run may be called reentrantly from any of the callouts to foreign |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 142 | // code (internal work, DoWork, DoIdleWork). As a result, DoWork and |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 143 | // DoIdleWork must be reentrant. |
[email protected] | 52a261f | 2009-03-03 15:01:12 | [diff] [blame] | 144 | // |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 145 | // NOTE 2: Run implementations must arrange for DoWork to be invoked as |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 146 | // expected if a callout to foreign code enters a message pump outside their |
| 147 | // control. For example, the MessageBox API on Windows pumps UI messages. If |
| 148 | // the MessageBox API is called (indirectly) from within Run, it is expected |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 149 | // that DoWork will be invoked from within that call in response to |
| 150 | // ScheduleWork or as requested by the last NextWorkInfo returned by DoWork. |
| 151 | // The MessagePump::Delegate may then elect to do nested work or not depending |
| 152 | // on its policy in that context. Regardless of that decision (and return |
| 153 | // value of the nested DoWork() call), DoWork() will be invoked again when the |
| 154 | // nested loop unwinds. |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 155 | virtual void Run(Delegate* delegate) = 0; |
| 156 | |
| 157 | // Quit immediately from the most recently entered run loop. This method may |
| 158 | // only be used on the thread that called Run. |
| 159 | virtual void Quit() = 0; |
| 160 | |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 161 | // Schedule a DoWork callback to happen reasonably soon. Does nothing if a |
| 162 | // DoWork callback is already scheduled. Once this call is made, DoWork is |
| 163 | // guaranteed to be called repeatedly at least until it returns a |
| 164 | // non-immediate NextWorkInfo. This call can be expensive and callers should |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 165 | // attempt not to invoke it again before a non-immediate NextWorkInfo was |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 166 | // returned from DoWork(). Thread-safe (and callers should avoid holding a |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 167 | // Lock at all cost while making this call as some platforms' priority |
| 168 | // boosting features have been observed to cause the caller to get descheduled |
| 169 | // : https://crbug.com/890978). |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 170 | virtual void ScheduleWork() = 0; |
| 171 | |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 172 | // Schedule a DoWork callback to happen at the specified time, cancelling any |
| 173 | // pending callback scheduled by this method. This method may only be used on |
| 174 | // the thread that called Run. |
Gabriel Charette | 066702b | 2019-02-28 18:12:55 | [diff] [blame] | 175 | // |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 176 | // It isn't necessary to call this during normal execution, as the pump wakes |
Etienne Pierre-doray | 2163f301 | 2020-04-02 21:37:14 | [diff] [blame] | 177 | // up as requested by the return value of DoWork(). |
Francois Doray | b61fcc11 | 2020-03-25 21:11:58 | [diff] [blame] | 178 | // TODO(crbug.com/885371): Determine if this must be called to ensure that |
| 179 | // delayed tasks run when a message pump outside the control of Run is |
| 180 | // entered. |
[email protected] | 7e7fab4 | 2010-11-06 22:23:29 | [diff] [blame] | 181 | virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0; |
[email protected] | 57cd3d2 | 2014-06-05 19:36:20 | [diff] [blame] | 182 | |
| 183 | // Sets the timer slack to the specified value. |
| 184 | virtual void SetTimerSlack(TimerSlack timer_slack); |
[email protected] | 295039bd | 2008-08-15 04:32:57 | [diff] [blame] | 185 | }; |
| 186 | |
| 187 | } // namespace base |
| 188 | |
[email protected] | 59e69e74 | 2013-06-18 20:27:52 | [diff] [blame] | 189 | #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ |