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