• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2010 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 #include "base/message_loop/message_pump.h"
6 
7 #include "base/check.h"
8 #include "base/message_loop/io_watcher.h"
9 #include "base/message_loop/message_pump_default.h"
10 #include "base/message_loop/message_pump_for_io.h"
11 #include "base/message_loop/message_pump_for_ui.h"
12 #include "base/notreached.h"
13 #include "base/task/current_thread.h"
14 #include "base/task/task_features.h"
15 #include "base/threading/platform_thread.h"
16 #include "build/build_config.h"
17 
18 #if BUILDFLAG(IS_APPLE)
19 #include "base/message_loop/message_pump_apple.h"
20 #endif
21 
22 namespace base {
23 
24 namespace {
25 
26 constexpr uint64_t kAlignWakeUpsMask = 1;
27 constexpr uint64_t kLeewayOffset = 1;
28 
PackAlignWakeUpsAndLeeway(bool align_wake_ups,TimeDelta leeway)29 constexpr uint64_t PackAlignWakeUpsAndLeeway(bool align_wake_ups,
30                                              TimeDelta leeway) {
31   return (static_cast<uint64_t>(leeway.InMilliseconds()) << kLeewayOffset) |
32          (align_wake_ups ? kAlignWakeUpsMask : 0);
33 }
34 
35 // This stores the current state of |kAlignWakeUps| and leeway. The last bit
36 // represents if |kAlignWakeUps| is enabled, and the other bits represent the
37 // leeway value applied to delayed tasks in milliseconds. An atomic is used here
38 // because the value is queried from multiple threads.
39 std::atomic<uint64_t> g_align_wake_ups_and_leeway =
40     PackAlignWakeUpsAndLeeway(false, kDefaultLeeway);
41 #if BUILDFLAG(IS_WIN)
42 bool g_explicit_high_resolution_timer_win = true;
43 #endif  // BUILDFLAG(IS_WIN)
44 
45 MessagePump::MessagePumpFactory* message_pump_for_ui_factory_ = nullptr;
46 
47 #if !BUILDFLAG(IS_NACL) && BUILDFLAG(IS_POSIX)
48 class MessagePumpForIOFdWatchImpl : public IOWatcher::FdWatch,
49                                     public MessagePumpForIO::FdWatcher {
50  public:
MessagePumpForIOFdWatchImpl(IOWatcher::FdWatcher * fd_watcher,const Location & location)51   MessagePumpForIOFdWatchImpl(IOWatcher::FdWatcher* fd_watcher,
52                               const Location& location)
53       : fd_watcher_(fd_watcher), controller_(location) {}
54 
~MessagePumpForIOFdWatchImpl()55   ~MessagePumpForIOFdWatchImpl() override {
56     controller_.StopWatchingFileDescriptor();
57   }
58 
controller()59   MessagePumpForIO::FdWatchController& controller() { return controller_; }
60 
61  private:
62   // MessagePumpForIO::FdWatcher:
OnFileCanReadWithoutBlocking(int fd)63   void OnFileCanReadWithoutBlocking(int fd) override {
64     fd_watcher_->OnFdReadable(fd);
65   }
66 
OnFileCanWriteWithoutBlocking(int fd)67   void OnFileCanWriteWithoutBlocking(int fd) override {
68     fd_watcher_->OnFdWritable(fd);
69   }
70 
71   const raw_ptr<IOWatcher::FdWatcher> fd_watcher_;
72   MessagePumpForIO::FdWatchController controller_;
73 };
74 #endif
75 
76 class IOWatcherForCurrentIOThread : public IOWatcher {
77  public:
IOWatcherForCurrentIOThread()78   IOWatcherForCurrentIOThread() : thread_(CurrentIOThread::Get()) {}
79 
80   // IOWatcher:
81 #if !BUILDFLAG(IS_NACL)
82 #if BUILDFLAG(IS_WIN)
RegisterIOHandlerImpl(HANDLE file,MessagePumpForIO::IOHandler * handler)83   bool RegisterIOHandlerImpl(HANDLE file,
84                              MessagePumpForIO::IOHandler* handler) override {
85     return thread_.RegisterIOHandler(file, handler);
86   }
87 
RegisterJobObjectImpl(HANDLE job,MessagePumpForIO::IOHandler * handler)88   bool RegisterJobObjectImpl(HANDLE job,
89                              MessagePumpForIO::IOHandler* handler) override {
90     return thread_.RegisterJobObject(job, handler);
91   }
92 #elif BUILDFLAG(IS_POSIX)
WatchFileDescriptorImpl(int fd,FdWatchDuration duration,FdWatchMode mode,FdWatcher & fd_watcher,const Location & location)93   std::unique_ptr<FdWatch> WatchFileDescriptorImpl(
94       int fd,
95       FdWatchDuration duration,
96       FdWatchMode mode,
97       FdWatcher& fd_watcher,
98       const Location& location) override {
99     MessagePumpForIO::Mode io_mode;
100     switch (mode) {
101       case FdWatchMode::kRead:
102         io_mode = MessagePumpForIO::WATCH_READ;
103         break;
104       case FdWatchMode::kWrite:
105         io_mode = MessagePumpForIO::WATCH_WRITE;
106         break;
107       case FdWatchMode::kReadWrite:
108         io_mode = MessagePumpForIO::WATCH_READ_WRITE;
109         break;
110     }
111     const bool is_persistent = duration == FdWatchDuration::kPersistent;
112     auto watch =
113         std::make_unique<MessagePumpForIOFdWatchImpl>(&fd_watcher, location);
114     if (!thread_.WatchFileDescriptor(fd, is_persistent, io_mode,
115                                      &watch->controller(), watch.get())) {
116       return nullptr;
117     }
118     return watch;
119   }
120 #endif
121 #if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && !BUILDFLAG(CRONET_BUILD))
WatchMachReceivePortImpl(mach_port_t port,MessagePumpForIO::MachPortWatchController * controller,MessagePumpForIO::MachPortWatcher * delegate)122   bool WatchMachReceivePortImpl(
123       mach_port_t port,
124       MessagePumpForIO::MachPortWatchController* controller,
125       MessagePumpForIO::MachPortWatcher* delegate) override {
126     return thread_.WatchMachReceivePort(port, controller, delegate);
127   }
128 #elif BUILDFLAG(IS_FUCHSIA)
WatchZxHandleImpl(zx_handle_t handle,bool persistent,zx_signals_t signals,MessagePumpForIO::ZxHandleWatchController * controller,MessagePumpForIO::ZxHandleWatcher * delegate)129   bool WatchZxHandleImpl(zx_handle_t handle,
130                          bool persistent,
131                          zx_signals_t signals,
132                          MessagePumpForIO::ZxHandleWatchController* controller,
133                          MessagePumpForIO::ZxHandleWatcher* delegate) override {
134     return thread_.WatchZxHandle(handle, persistent, signals, controller,
135                                  delegate);
136   }
137 #endif  // BUILDFLAG(IS_FUCHSIA)
138 #endif  // !BUILDFLAG(IS_NACL)
139 
140  private:
141   CurrentIOThread thread_;
142 };
143 
144 }  // namespace
145 
146 MessagePump::MessagePump() = default;
147 
148 MessagePump::~MessagePump() = default;
149 
HandleNestedNativeLoopWithApplicationTasks(bool application_tasks_desired)150 bool MessagePump::HandleNestedNativeLoopWithApplicationTasks(
151     bool application_tasks_desired) {
152   return false;
153 }
154 
155 // static
OverrideMessagePumpForUIFactory(MessagePumpFactory * factory)156 void MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactory* factory) {
157   DCHECK(!message_pump_for_ui_factory_);
158   message_pump_for_ui_factory_ = factory;
159 }
160 
161 // static
IsMessagePumpForUIFactoryOveridden()162 bool MessagePump::IsMessagePumpForUIFactoryOveridden() {
163   return message_pump_for_ui_factory_ != nullptr;
164 }
165 
166 // static
Create(MessagePumpType type)167 std::unique_ptr<MessagePump> MessagePump::Create(MessagePumpType type) {
168   switch (type) {
169     case MessagePumpType::UI:
170       if (message_pump_for_ui_factory_)
171         return message_pump_for_ui_factory_();
172 #if BUILDFLAG(IS_APPLE)
173       return message_pump_apple::Create();
174 #elif BUILDFLAG(IS_NACL) || BUILDFLAG(IS_AIX)
175       // Currently NaCl and AIX don't have a UI MessagePump.
176       // TODO(abarth): Figure out if we need this.
177       NOTREACHED();
178 #elif BUILDFLAG(IS_ANDROID)
179       {
180         auto message_pump = std::make_unique<MessagePumpAndroid>();
181         message_pump->set_is_type_ui(true);
182         return message_pump;
183       }
184 #else
185       return std::make_unique<MessagePumpForUI>();
186 #endif
187 
188     case MessagePumpType::IO:
189       return std::make_unique<MessagePumpForIO>();
190 
191 #if BUILDFLAG(IS_ANDROID)
192     case MessagePumpType::JAVA:
193       return std::make_unique<MessagePumpAndroid>();
194 #endif
195 
196 #if BUILDFLAG(IS_APPLE)
197     case MessagePumpType::NS_RUNLOOP:
198       return std::make_unique<MessagePumpNSRunLoop>();
199 #endif
200 
201     case MessagePumpType::CUSTOM:
202       NOTREACHED();
203 
204     case MessagePumpType::DEFAULT:
205 #if BUILDFLAG(IS_IOS)
206       // On iOS, a native runloop is always required to pump system work.
207       return std::make_unique<MessagePumpCFRunLoop>();
208 #else
209       return std::make_unique<MessagePumpDefault>();
210 #endif
211   }
212 }
213 
214 // static
InitializeFeatures()215 void MessagePump::InitializeFeatures() {
216   ResetAlignWakeUpsState();
217 #if BUILDFLAG(IS_WIN)
218   g_explicit_high_resolution_timer_win =
219       FeatureList::IsEnabled(kExplicitHighResolutionTimerWin);
220   MessagePumpWin::InitializeFeatures();
221 #elif BUILDFLAG(IS_ANDROID)
222   MessagePumpAndroid::InitializeFeatures();
223 #endif
224 }
225 
226 // static
OverrideAlignWakeUpsState(bool enabled,TimeDelta leeway)227 void MessagePump::OverrideAlignWakeUpsState(bool enabled, TimeDelta leeway) {
228   g_align_wake_ups_and_leeway.store(PackAlignWakeUpsAndLeeway(enabled, leeway),
229                                     std::memory_order_relaxed);
230 }
231 
232 // static
ResetAlignWakeUpsState()233 void MessagePump::ResetAlignWakeUpsState() {
234   OverrideAlignWakeUpsState(FeatureList::IsEnabled(kAlignWakeUps),
235                             kTaskLeewayParam.Get());
236 }
237 
238 // static
GetAlignWakeUpsEnabled()239 bool MessagePump::GetAlignWakeUpsEnabled() {
240   return g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) &
241          kAlignWakeUpsMask;
242 }
243 
244 // static
GetLeewayIgnoringThreadOverride()245 TimeDelta MessagePump::GetLeewayIgnoringThreadOverride() {
246   return Milliseconds(
247       g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) >>
248       kLeewayOffset);
249 }
250 
251 // static
GetLeewayForCurrentThread()252 TimeDelta MessagePump::GetLeewayForCurrentThread() {
253   // For some threads, there might be an override of the leeway, so check it
254   // first.
255   auto leeway_override = PlatformThread::GetThreadLeewayOverride();
256   if (leeway_override.has_value()) {
257     return leeway_override.value();
258   }
259   return GetLeewayIgnoringThreadOverride();
260 }
261 
AdjustDelayedRunTime(TimeTicks earliest_time,TimeTicks run_time,TimeTicks latest_time)262 TimeTicks MessagePump::AdjustDelayedRunTime(TimeTicks earliest_time,
263                                             TimeTicks run_time,
264                                             TimeTicks latest_time) {
265   // Windows relies on the low resolution timer rather than manual wake up
266   // alignment when the leeway is less than the OS default timer resolution.
267 #if BUILDFLAG(IS_WIN)
268   if (g_explicit_high_resolution_timer_win &&
269       GetLeewayForCurrentThread() <=
270           Milliseconds(Time::kMinLowResolutionThresholdMs)) {
271     return earliest_time;
272   }
273 #endif  // BUILDFLAG(IS_WIN)
274   if (GetAlignWakeUpsEnabled()) {
275     TimeTicks aligned_run_time = earliest_time.SnappedToNextTick(
276         TimeTicks(), GetLeewayForCurrentThread());
277     return std::min(aligned_run_time, latest_time);
278   }
279   return run_time;
280 }
281 
GetIOWatcher()282 IOWatcher* MessagePump::GetIOWatcher() {
283   // By default only "IO thread" message pumps support async IO.
284   //
285   // TODO(crbug.com/379190028): This is done for convenience given the
286   // preexistence of CurrentIOThread, but we should eventually remove this in
287   // favor of each IO MessagePump implementation defining their own override.
288   if (!io_watcher_ && CurrentIOThread::IsSet()) {
289     io_watcher_ = std::make_unique<IOWatcherForCurrentIOThread>();
290   }
291   return io_watcher_.get();
292 }
293 
294 }  // namespace base
295