Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2062ca1

Browse files
Avoid spurious descheduling when posting message loop tasks. (#3812)
Closes dart-lang/sdk#29971
1 parent 8d5372a commit 2062ca1

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

fml/message_loop_impl.cc

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,33 @@ void MessageLoopImpl::RegisterTask(ftl::Closure task,
111111
// |task| synchronously within this function.
112112
return;
113113
}
114-
ftl::MutexLocker lock(&delayed_tasks_mutex_);
115-
delayed_tasks_.push({++order_, std::move(task), target_time});
116-
WakeUp(delayed_tasks_.top().target_time);
114+
115+
ftl::TimePoint previous_wakeup, new_wakeup;
116+
{
117+
ftl::MutexLocker lock(&delayed_tasks_mutex_);
118+
if (delayed_tasks_.empty()) {
119+
previous_wakeup = ftl::TimePoint::Max();
120+
} else {
121+
previous_wakeup = delayed_tasks_.top().target_time;
122+
}
123+
delayed_tasks_.push({++order_, std::move(task), target_time});
124+
new_wakeup = delayed_tasks_.top().target_time;
125+
}
126+
if (new_wakeup < previous_wakeup) {
127+
WakeUp(new_wakeup);
128+
}
117129
}
118130

119131
void MessageLoopImpl::RunExpiredTasks() {
120132
TRACE_EVENT0("fml", "MessageLoop::RunExpiredTasks");
121133
std::vector<ftl::Closure> invocations;
122134

135+
ftl::TimePoint new_wakeup;
123136
{
124137
ftl::MutexLocker lock(&delayed_tasks_mutex_);
125138

126139
if (delayed_tasks_.empty()) {
140+
FTL_DCHECK(terminated_); // No spurious wakeups except shutdown.
127141
return;
128142
}
129143

@@ -137,9 +151,13 @@ void MessageLoopImpl::RunExpiredTasks() {
137151
delayed_tasks_.pop();
138152
}
139153

140-
WakeUp(delayed_tasks_.empty() ? ftl::TimePoint::Max()
141-
: delayed_tasks_.top().target_time);
154+
if (delayed_tasks_.empty()) {
155+
new_wakeup = ftl::TimePoint::Max();
156+
} else {
157+
new_wakeup = delayed_tasks_.top().target_time;
158+
}
142159
}
160+
WakeUp(new_wakeup);
143161

144162
for (const auto& invocation : invocations) {
145163
invocation();

fml/message_loop_unittests.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,34 @@ TEST(MessageLoop, CheckRunsTaskOnCurrentThread) {
140140
thread.join();
141141
}
142142

143+
TEST(MessageLoop, TIME_SENSITIVE(NewTaskDueBeforePendingTask)) {
144+
intptr_t tasks_run = 0;
145+
std::thread thread([&tasks_run]() {
146+
fml::MessageLoop::EnsureInitializedForCurrentThread();
147+
auto& loop = fml::MessageLoop::GetCurrent();
148+
auto begin = ftl::TimePoint::Now();
149+
loop.GetTaskRunner()->PostDelayedTask(
150+
[&tasks_run]() {
151+
ASSERT_EQ(tasks_run, 1);
152+
tasks_run++;
153+
fml::MessageLoop::GetCurrent().Terminate();
154+
},
155+
ftl::TimeDelta::FromMilliseconds(15));
156+
loop.GetTaskRunner()->PostDelayedTask(
157+
[begin, &tasks_run]() {
158+
ASSERT_EQ(tasks_run, 0);
159+
tasks_run++;
160+
auto delta = ftl::TimePoint::Now() - begin;
161+
auto ms = delta.ToMillisecondsF();
162+
ASSERT_LE(ms, 15); // Did not wait for previous wakeup time.
163+
},
164+
ftl::TimeDelta::FromMilliseconds(5));
165+
loop.Run();
166+
});
167+
thread.join();
168+
ASSERT_EQ(tasks_run, 2);
169+
}
170+
143171
TEST(MessageLoop, TIME_SENSITIVE(SingleDelayedTaskByDelta)) {
144172
bool checked = false;
145173
std::thread thread([&checked]() {

testing/run_tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
set -ex
44

55
out/host_debug_unopt/ftl_unittests
6+
out/host_debug_unopt/fml_unittests
67
out/host_debug_unopt/synchronization_unittests
78
out/host_debug_unopt/wtf_unittests
89

0 commit comments

Comments
 (0)