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

Commit 6f5347c

Browse files
authored
MessageLoopTaskQueue schedules Wakes (#9316)
* Refactor to move Task Queue to its own class - This is to help with sharing task queue among multiple message loops going forward. - currently there is 1:1 mapping between task queue and message loop, we are still maintaining the semantics for this change. * Add mutex include * Most of the waking up changes minus test failures * Refactor MessageLoopImpl to be Wakeable - Makes testing easier by letting us putting a TestWakeable - Also move the waking up logic to the task queue * add tests * Fix formatting and license
1 parent b9c790e commit 6f5347c

8 files changed

Lines changed: 125 additions & 22 deletions

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ FILE: ../../../flutter/fml/trace_event.h
224224
FILE: ../../../flutter/fml/unique_fd.cc
225225
FILE: ../../../flutter/fml/unique_fd.h
226226
FILE: ../../../flutter/fml/unique_object.h
227+
FILE: ../../../flutter/fml/wakeable.h
227228
FILE: ../../../flutter/lib/io/dart_io.cc
228229
FILE: ../../../flutter/lib/io/dart_io.h
229230
FILE: ../../../flutter/lib/snapshot/libraries.json

fml/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ source_set("fml") {
7777
"unique_fd.cc",
7878
"unique_fd.h",
7979
"unique_object.h",
80+
"wakeable.h",
8081
]
8182

8283
public_deps = []

fml/message_loop_impl.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fml::RefPtr<MessageLoopImpl> MessageLoopImpl::Create() {
4141

4242
MessageLoopImpl::MessageLoopImpl() : terminated_(false) {
4343
task_queue_ = std::make_unique<MessageLoopTaskQueue>();
44+
task_queue_->SetWakeable(this);
4445
}
4546

4647
MessageLoopImpl::~MessageLoopImpl() = default;
@@ -53,8 +54,7 @@ void MessageLoopImpl::PostTask(fml::closure task, fml::TimePoint target_time) {
5354
// |task| synchronously within this function.
5455
return;
5556
}
56-
const auto wake_up = task_queue_->RegisterTask(task, target_time);
57-
WakeUp(wake_up);
57+
task_queue_->RegisterTask(task, target_time);
5858
}
5959

6060
void MessageLoopImpl::AddTaskObserver(intptr_t key, fml::closure callback) {
@@ -130,9 +130,7 @@ void MessageLoopImpl::FlushTasks(FlushType type) {
130130
// gather invocations -> Swap -> execute invocations
131131
// will lead us to run invocations on the wrong thread.
132132
std::lock_guard<std::mutex> task_flush_lock(tasks_flushing_mutex_);
133-
134-
const auto wake_up = task_queue_->GetTasksToRunNow(type, invocations);
135-
WakeUp(wake_up);
133+
task_queue_->GetTasksToRunNow(type, invocations);
136134

137135
for (const auto& invocation : invocations) {
138136
invocation();

fml/message_loop_impl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
#include "flutter/fml/message_loop_task_queue.h"
2121
#include "flutter/fml/synchronization/thread_annotations.h"
2222
#include "flutter/fml/time/time_point.h"
23+
#include "flutter/fml/wakeable.h"
2324

2425
namespace fml {
2526

26-
class MessageLoopImpl : public fml::RefCountedThreadSafe<MessageLoopImpl> {
27+
class MessageLoopImpl : public Wakeable,
28+
public fml::RefCountedThreadSafe<MessageLoopImpl> {
2729
public:
2830
static fml::RefPtr<MessageLoopImpl> Create();
2931

@@ -33,8 +35,6 @@ class MessageLoopImpl : public fml::RefCountedThreadSafe<MessageLoopImpl> {
3335

3436
virtual void Terminate() = 0;
3537

36-
virtual void WakeUp(fml::TimePoint time_point) = 0;
37-
3838
void PostTask(fml::closure task, fml::TimePoint target_time);
3939

4040
void AddTaskObserver(intptr_t key, fml::closure callback);

fml/message_loop_task_queue.cc

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define FML_USED_ON_EMBEDDER
66

77
#include "flutter/fml/message_loop_task_queue.h"
8+
#include "flutter/fml/message_loop_impl.h"
89

910
namespace fml {
1011

@@ -17,19 +18,19 @@ void MessageLoopTaskQueue::Dispose() {
1718
delayed_tasks_ = {};
1819
}
1920

20-
fml::TimePoint MessageLoopTaskQueue::RegisterTask(fml::closure task,
21-
fml::TimePoint target_time) {
21+
void MessageLoopTaskQueue::RegisterTask(fml::closure task,
22+
fml::TimePoint target_time) {
2223
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
2324
delayed_tasks_.push({++order_, std::move(task), target_time});
24-
return delayed_tasks_.top().GetTargetTime();
25+
WakeUp(delayed_tasks_.top().GetTargetTime());
2526
}
2627

2728
bool MessageLoopTaskQueue::HasPendingTasks() {
2829
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
2930
return !delayed_tasks_.empty();
3031
}
3132

32-
fml::TimePoint MessageLoopTaskQueue::GetTasksToRunNow(
33+
void MessageLoopTaskQueue::GetTasksToRunNow(
3334
FlushType type,
3435
std::vector<fml::closure>& invocations) {
3536
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
@@ -48,9 +49,15 @@ fml::TimePoint MessageLoopTaskQueue::GetTasksToRunNow(
4849
}
4950

5051
if (delayed_tasks_.empty()) {
51-
return fml::TimePoint::Max();
52+
WakeUp(fml::TimePoint::Max());
5253
} else {
53-
return delayed_tasks_.top().GetTargetTime();
54+
WakeUp(delayed_tasks_.top().GetTargetTime());
55+
}
56+
}
57+
58+
void MessageLoopTaskQueue::WakeUp(fml::TimePoint time) {
59+
if (wakeable_) {
60+
wakeable_->WakeUp(time);
5461
}
5562
}
5663

@@ -94,4 +101,8 @@ void MessageLoopTaskQueue::Swap(MessageLoopTaskQueue& other)
94101
std::swap(delayed_tasks_, other.delayed_tasks_);
95102
}
96103

104+
void MessageLoopTaskQueue::SetWakeable(fml::Wakeable* wakeable) {
105+
wakeable_ = wakeable;
106+
}
107+
97108
} // namespace fml

fml/message_loop_task_queue.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "flutter/fml/macros.h"
1515
#include "flutter/fml/memory/ref_counted.h"
1616
#include "flutter/fml/synchronization/thread_annotations.h"
17+
#include "flutter/fml/wakeable.h"
1718

1819
namespace fml {
1920

@@ -23,7 +24,8 @@ enum class FlushType {
2324
};
2425

2526
// This class keeps track of all the tasks and observers that
26-
// need to be run on it's MessageLoopImpl.
27+
// need to be run on it's MessageLoopImpl. This also wakes up the
28+
// loop at the required times.
2729
class MessageLoopTaskQueue {
2830
public:
2931
// Lifecycle.
@@ -36,13 +38,11 @@ class MessageLoopTaskQueue {
3638

3739
// Tasks methods.
3840

39-
fml::TimePoint RegisterTask(fml::closure task, fml::TimePoint target_time);
41+
void RegisterTask(fml::closure task, fml::TimePoint target_time);
4042

4143
bool HasPendingTasks();
4244

43-
// Returns the wake up time.
44-
fml::TimePoint GetTasksToRunNow(FlushType type,
45-
std::vector<fml::closure>& invocations);
45+
void GetTasksToRunNow(FlushType type, std::vector<fml::closure>& invocations);
4646

4747
size_t GetNumPendingTasks();
4848

@@ -58,7 +58,13 @@ class MessageLoopTaskQueue {
5858

5959
void Swap(MessageLoopTaskQueue& other);
6060

61+
void SetWakeable(fml::Wakeable* wakeable);
62+
6163
private:
64+
void WakeUp(fml::TimePoint time);
65+
66+
Wakeable* wakeable_ = NULL;
67+
6268
std::mutex observers_mutex_;
6369
std::map<intptr_t, fml::closure> task_observers_
6470
FML_GUARDED_BY(observers_mutex_);

fml/message_loop_task_queue_unittests.cc

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,37 @@
55
#define FML_USED_ON_EMBEDDER
66

77
#include "flutter/fml/message_loop_task_queue.h"
8+
#include "flutter/fml/synchronization/count_down_latch.h"
9+
#include "flutter/fml/synchronization/waitable_event.h"
810
#include "gtest/gtest.h"
911

12+
class TestWakeable : public fml::Wakeable {
13+
public:
14+
using WakeUpCall = std::function<void(const fml::TimePoint)>;
15+
16+
TestWakeable(WakeUpCall call) : wake_up_call_(call) {}
17+
18+
void WakeUp(fml::TimePoint time_point) override { wake_up_call_(time_point); }
19+
20+
private:
21+
WakeUpCall wake_up_call_;
22+
};
23+
1024
TEST(MessageLoopTaskQueue, StartsWithNoPendingTasks) {
1125
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
1226
ASSERT_FALSE(task_queue->HasPendingTasks());
1327
}
1428

1529
TEST(MessageLoopTaskQueue, RegisterOneTask) {
16-
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
1730
const auto time = fml::TimePoint::Max();
18-
const auto wake_time = task_queue->RegisterTask([] {}, time);
31+
32+
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
33+
task_queue->SetWakeable(new TestWakeable(
34+
[&time](fml::TimePoint wake_time) { ASSERT_TRUE(wake_time == time); }));
35+
36+
task_queue->RegisterTask([] {}, time);
1937
ASSERT_TRUE(task_queue->HasPendingTasks());
2038
ASSERT_TRUE(task_queue->GetNumPendingTasks() == 1);
21-
ASSERT_TRUE(wake_time == time);
2239
}
2340

2441
TEST(MessageLoopTaskQueue, RegisterTwoTasksAndCount) {
@@ -68,3 +85,51 @@ TEST(MessageLoopTaskQueue, AddRemoveNotifyObservers) {
6885
task_queue->NotifyObservers();
6986
ASSERT_TRUE(test_val == 0);
7087
}
88+
89+
TEST(MessageLoopTaskQueue, WakeUpIndependentOfTime) {
90+
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
91+
92+
int num_wakes = 0;
93+
task_queue->SetWakeable(new TestWakeable(
94+
[&num_wakes](fml::TimePoint wake_time) { ++num_wakes; }));
95+
96+
task_queue->RegisterTask([]() {}, fml::TimePoint::Now());
97+
task_queue->RegisterTask([]() {}, fml::TimePoint::Max());
98+
99+
ASSERT_TRUE(num_wakes == 2);
100+
}
101+
102+
TEST(MessageLoopTaskQueue, WakeUpWithMaxIfNoInvocations) {
103+
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
104+
fml::AutoResetWaitableEvent ev;
105+
106+
task_queue->SetWakeable(new TestWakeable([&ev](fml::TimePoint wake_time) {
107+
ASSERT_TRUE(wake_time == fml::TimePoint::Max());
108+
ev.Signal();
109+
}));
110+
111+
std::vector<fml::closure> invocations;
112+
task_queue->GetTasksToRunNow(fml::FlushType::kAll, invocations);
113+
ev.Wait();
114+
}
115+
116+
TEST(MessageLoopTaskQueue, WokenUpWithNewerTime) {
117+
auto task_queue = std::make_unique<fml::MessageLoopTaskQueue>();
118+
fml::CountDownLatch latch(2);
119+
120+
fml::TimePoint expected = fml::TimePoint::Max();
121+
122+
task_queue->SetWakeable(
123+
new TestWakeable([&latch, &expected](fml::TimePoint wake_time) {
124+
ASSERT_TRUE(wake_time == expected);
125+
latch.CountDown();
126+
}));
127+
128+
task_queue->RegisterTask([]() {}, fml::TimePoint::Max());
129+
130+
const auto now = fml::TimePoint::Now();
131+
expected = now;
132+
task_queue->RegisterTask([]() {}, now);
133+
134+
latch.Wait();
135+
}

fml/wakeable.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FML_WAKEABLE_H_
6+
#define FLUTTER_FML_WAKEABLE_H_
7+
8+
#include "flutter/fml/time/time_point.h"
9+
10+
namespace fml {
11+
12+
class Wakeable {
13+
public:
14+
virtual ~Wakeable() {}
15+
16+
virtual void WakeUp(fml::TimePoint time_point) = 0;
17+
};
18+
19+
} // namespace fml
20+
21+
#endif // FLUTTER_FML_WAKEABLE_H_

0 commit comments

Comments
 (0)