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/message_pump_default.h"
9 #include "base/message_loop/message_pump_for_io.h"
10 #include "base/message_loop/message_pump_for_ui.h"
11 #include "base/notreached.h"
12 #include "base/task/task_features.h"
13 #include "base/threading/platform_thread.h"
14 #include "build/build_config.h"
15
16 #if BUILDFLAG(IS_APPLE)
17 #include "base/message_loop/message_pump_apple.h"
18 #endif
19
20 namespace base {
21
22 namespace {
23
24 constexpr uint64_t kAlignWakeUpsMask = 1;
25 constexpr uint64_t kLeewayOffset = 1;
26
PackAlignWakeUpsAndLeeway(bool align_wake_ups,TimeDelta leeway)27 constexpr uint64_t PackAlignWakeUpsAndLeeway(bool align_wake_ups,
28 TimeDelta leeway) {
29 return (static_cast<uint64_t>(leeway.InMilliseconds()) << kLeewayOffset) |
30 (align_wake_ups ? kAlignWakeUpsMask : 0);
31 }
32
33 // This stores the current state of |kAlignWakeUps| and leeway. The last bit
34 // represents if |kAlignWakeUps| is enabled, and the other bits represent the
35 // leeway value applied to delayed tasks in milliseconds. An atomic is used here
36 // because the value is queried from multiple threads.
37 std::atomic<uint64_t> g_align_wake_ups_and_leeway =
38 PackAlignWakeUpsAndLeeway(false, kDefaultLeeway);
39 #if BUILDFLAG(IS_WIN)
40 bool g_explicit_high_resolution_timer_win = true;
41 #endif // BUILDFLAG(IS_WIN)
42
43 MessagePump::MessagePumpFactory* message_pump_for_ui_factory_ = nullptr;
44
45 } // namespace
46
47 MessagePump::MessagePump() = default;
48
49 MessagePump::~MessagePump() = default;
50
HandleNestedNativeLoopWithApplicationTasks(bool application_tasks_desired)51 bool MessagePump::HandleNestedNativeLoopWithApplicationTasks(
52 bool application_tasks_desired) {
53 return false;
54 }
55
56 // static
OverrideMessagePumpForUIFactory(MessagePumpFactory * factory)57 void MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactory* factory) {
58 DCHECK(!message_pump_for_ui_factory_);
59 message_pump_for_ui_factory_ = factory;
60 }
61
62 // static
IsMessagePumpForUIFactoryOveridden()63 bool MessagePump::IsMessagePumpForUIFactoryOveridden() {
64 return message_pump_for_ui_factory_ != nullptr;
65 }
66
67 // static
Create(MessagePumpType type)68 std::unique_ptr<MessagePump> MessagePump::Create(MessagePumpType type) {
69 switch (type) {
70 case MessagePumpType::UI:
71 if (message_pump_for_ui_factory_)
72 return message_pump_for_ui_factory_();
73 #if BUILDFLAG(IS_APPLE)
74 return message_pump_apple::Create();
75 #elif BUILDFLAG(IS_NACL) || BUILDFLAG(IS_AIX)
76 // Currently NaCl and AIX don't have a UI MessagePump.
77 // TODO(abarth): Figure out if we need this.
78 NOTREACHED();
79 return nullptr;
80 #elif BUILDFLAG(IS_ANDROID)
81 {
82 auto message_pump = std::make_unique<MessagePumpAndroid>();
83 message_pump->set_is_type_ui(true);
84 return message_pump;
85 }
86 #else
87 return std::make_unique<MessagePumpForUI>();
88 #endif
89
90 case MessagePumpType::IO:
91 return std::make_unique<MessagePumpForIO>();
92
93 #if BUILDFLAG(IS_ANDROID)
94 case MessagePumpType::JAVA:
95 return std::make_unique<MessagePumpAndroid>();
96 #endif
97
98 #if BUILDFLAG(IS_APPLE)
99 case MessagePumpType::NS_RUNLOOP:
100 return std::make_unique<MessagePumpNSRunLoop>();
101 #endif
102
103 case MessagePumpType::CUSTOM:
104 NOTREACHED();
105 return nullptr;
106
107 case MessagePumpType::DEFAULT:
108 #if BUILDFLAG(IS_IOS)
109 // On iOS, a native runloop is always required to pump system work.
110 return std::make_unique<MessagePumpCFRunLoop>();
111 #else
112 return std::make_unique<MessagePumpDefault>();
113 #endif
114 }
115 }
116
117 // static
InitializeFeatures()118 void MessagePump::InitializeFeatures() {
119 ResetAlignWakeUpsState();
120 #if BUILDFLAG(IS_WIN)
121 g_explicit_high_resolution_timer_win =
122 FeatureList::IsEnabled(kExplicitHighResolutionTimerWin);
123 MessagePumpWin::InitializeFeatures();
124 #endif
125 }
126
127 // static
OverrideAlignWakeUpsState(bool enabled,TimeDelta leeway)128 void MessagePump::OverrideAlignWakeUpsState(bool enabled, TimeDelta leeway) {
129 g_align_wake_ups_and_leeway.store(PackAlignWakeUpsAndLeeway(enabled, leeway),
130 std::memory_order_relaxed);
131 }
132
133 // static
ResetAlignWakeUpsState()134 void MessagePump::ResetAlignWakeUpsState() {
135 OverrideAlignWakeUpsState(FeatureList::IsEnabled(kAlignWakeUps),
136 kTaskLeewayParam.Get());
137 }
138
139 // static
GetAlignWakeUpsEnabled()140 bool MessagePump::GetAlignWakeUpsEnabled() {
141 return g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) &
142 kAlignWakeUpsMask;
143 }
144
145 // static
GetLeewayIgnoringThreadOverride()146 TimeDelta MessagePump::GetLeewayIgnoringThreadOverride() {
147 return Milliseconds(
148 g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) >>
149 kLeewayOffset);
150 }
151
152 // static
GetLeewayForCurrentThread()153 TimeDelta MessagePump::GetLeewayForCurrentThread() {
154 // For some threads, there might be an override of the leeway, so check it
155 // first.
156 auto leeway_override = PlatformThread::GetThreadLeewayOverride();
157 if (leeway_override.has_value()) {
158 return leeway_override.value();
159 }
160 return GetLeewayIgnoringThreadOverride();
161 }
162
AdjustDelayedRunTime(TimeTicks earliest_time,TimeTicks run_time,TimeTicks latest_time)163 TimeTicks MessagePump::AdjustDelayedRunTime(TimeTicks earliest_time,
164 TimeTicks run_time,
165 TimeTicks latest_time) {
166 // Windows relies on the low resolution timer rather than manual wake up
167 // alignment when the leeway is less than the OS default timer resolution.
168 #if BUILDFLAG(IS_WIN)
169 if (g_explicit_high_resolution_timer_win &&
170 GetLeewayForCurrentThread() <=
171 Milliseconds(Time::kMinLowResolutionThresholdMs)) {
172 return earliest_time;
173 }
174 #endif // BUILDFLAG(IS_WIN)
175 if (GetAlignWakeUpsEnabled()) {
176 TimeTicks aligned_run_time = earliest_time.SnappedToNextTick(
177 TimeTicks(), GetLeewayForCurrentThread());
178 return std::min(aligned_run_time, latest_time);
179 }
180 return run_time;
181 }
182
183 } // namespace base
184