forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
message_loop_impl.cc
148 lines (121 loc) · 4.3 KB
/
message_loop_impl.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#define FML_USED_ON_EMBEDDER
#include "flutter/fml/message_loop_impl.h"
#include <algorithm>
#include <vector>
#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#if OS_MACOSX
#include "flutter/fml/platform/darwin/message_loop_darwin.h"
#elif OS_ANDROID
#include "flutter/fml/platform/android/message_loop_android.h"
#elif OS_LINUX
#include "flutter/fml/platform/linux/message_loop_linux.h"
#elif OS_WIN
#include "flutter/fml/platform/win/message_loop_win.h"
#endif
namespace fml {
fml::RefPtr<MessageLoopImpl> MessageLoopImpl::Create() {
#if OS_MACOSX
return fml::MakeRefCounted<MessageLoopDarwin>();
#elif OS_ANDROID
return fml::MakeRefCounted<MessageLoopAndroid>();
#elif OS_LINUX
return fml::MakeRefCounted<MessageLoopLinux>();
#elif OS_WIN
return fml::MakeRefCounted<MessageLoopWin>();
#else
return nullptr;
#endif
}
MessageLoopImpl::MessageLoopImpl() : order_(0), terminated_(false) {}
MessageLoopImpl::~MessageLoopImpl() = default;
void MessageLoopImpl::PostTask(fml::closure task, fml::TimePoint target_time) {
FML_DCHECK(task != nullptr);
RegisterTask(task, target_time);
}
void MessageLoopImpl::RunExpiredTasksNow() {
RunExpiredTasks();
}
void MessageLoopImpl::AddTaskObserver(intptr_t key, fml::closure callback) {
FML_DCHECK(callback != nullptr);
FML_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this)
<< "Message loop task observer must be added on the same thread as the "
"loop.";
task_observers_[key] = std::move(callback);
}
void MessageLoopImpl::RemoveTaskObserver(intptr_t key) {
FML_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this)
<< "Message loop task observer must be removed from the same thread as "
"the loop.";
task_observers_.erase(key);
}
void MessageLoopImpl::DoRun() {
if (terminated_) {
// Message loops may be run only once.
return;
}
// Allow the implementation to do its thing.
Run();
// The loop may have been implicitly terminated. This can happen if the
// implementation supports termination via platform specific APIs or just
// error conditions. Set the terminated flag manually.
terminated_ = true;
// The message loop is shutting down. Check if there are expired tasks. This
// is the last chance for expired tasks to be serviced. Make sure the
// terminated flag is already set so we don't accrue additional tasks now.
RunExpiredTasksNow();
// When the message loop is in the process of shutting down, pending tasks
// should be destructed on the message loop's thread. We have just returned
// from the implementations |Run| method which we know is on the correct
// thread. Drop all pending tasks on the floor.
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
delayed_tasks_ = {};
}
void MessageLoopImpl::DoTerminate() {
terminated_ = true;
Terminate();
}
void MessageLoopImpl::RegisterTask(fml::closure task,
fml::TimePoint target_time) {
FML_DCHECK(task != nullptr);
if (terminated_) {
// If the message loop has already been terminated, PostTask should destruct
// |task| synchronously within this function.
return;
}
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
delayed_tasks_.push({++order_, std::move(task), target_time});
WakeUp(delayed_tasks_.top().target_time);
}
void MessageLoopImpl::RunExpiredTasks() {
TRACE_EVENT0("fml", "MessageLoop::RunExpiredTasks");
std::vector<fml::closure> invocations;
{
std::lock_guard<std::mutex> lock(delayed_tasks_mutex_);
if (delayed_tasks_.empty()) {
return;
}
auto now = fml::TimePoint::Now();
while (!delayed_tasks_.empty()) {
const auto& top = delayed_tasks_.top();
if (top.target_time > now) {
break;
}
invocations.emplace_back(std::move(top.task));
delayed_tasks_.pop();
}
WakeUp(delayed_tasks_.empty() ? fml::TimePoint::Max()
: delayed_tasks_.top().target_time);
}
for (const auto& invocation : invocations) {
invocation();
for (const auto& observer : task_observers_) {
observer.second();
}
}
}
} // namespace fml