1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/base/android_task_runner.h"
18
19 #include <errno.h>
20 #include <sys/eventfd.h>
21 #include <sys/timerfd.h>
22
23 namespace perfetto {
24 namespace base {
25
AndroidTaskRunner()26 AndroidTaskRunner::AndroidTaskRunner()
27 : looper_(ALooper_prepare(0 /* require callbacks */)),
28 immediate_event_(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)),
29 delayed_timer_(
30 timerfd_create(kWallTimeClockSource, TFD_NONBLOCK | TFD_CLOEXEC)) {
31 ALooper_acquire(looper_);
32 PERFETTO_CHECK(immediate_event_);
33 PERFETTO_CHECK(delayed_timer_);
34 AddFileDescriptorWatch(immediate_event_.get(),
35 std::bind(&AndroidTaskRunner::RunImmediateTask, this));
36 AddFileDescriptorWatch(delayed_timer_.get(),
37 std::bind(&AndroidTaskRunner::RunDelayedTask, this));
38 }
39
~AndroidTaskRunner()40 AndroidTaskRunner::~AndroidTaskRunner() {
41 PERFETTO_DCHECK_THREAD(thread_checker_);
42 std::lock_guard<std::mutex> lock(lock_);
43 for (const auto& watch : watch_tasks_) {
44 // ALooper doesn't guarantee that each watch doesn't run one last time if
45 // the file descriptor was already signalled. To guard against this point
46 // the watch to a no-op callback.
47 ALooper_addFd(
48 looper_, watch.first, ALOOPER_POLL_CALLBACK,
49 ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP,
50 [](int, int, void*) -> int { return 0; }, nullptr);
51 ALooper_removeFd(looper_, watch.first);
52 }
53 ALooper_release(looper_);
54
55 struct itimerspec time = {};
56 timerfd_settime(delayed_timer_.get(), TFD_TIMER_ABSTIME, &time, nullptr);
57 }
58
Run()59 void AndroidTaskRunner::Run() {
60 quit_ = false;
61 while (true) {
62 {
63 std::lock_guard<std::mutex> lock(lock_);
64 if (quit_)
65 break;
66 }
67 ALooper_pollOnce(-1 /* timeout */, nullptr, nullptr, nullptr);
68 }
69 }
70
Quit()71 void AndroidTaskRunner::Quit() {
72 std::lock_guard<std::mutex> lock(lock_);
73 quit_ = true;
74 ALooper_wake(looper_);
75 }
76
IsIdleForTesting()77 bool AndroidTaskRunner::IsIdleForTesting() {
78 PERFETTO_DCHECK_THREAD(thread_checker_);
79 std::lock_guard<std::mutex> lock(lock_);
80 return immediate_tasks_.empty();
81 }
82
RunImmediateTask()83 void AndroidTaskRunner::RunImmediateTask() {
84 uint64_t unused = 0;
85 if (read(immediate_event_.get(), &unused, sizeof(unused)) != sizeof(unused) &&
86 errno != EAGAIN) {
87 PERFETTO_DPLOG("read");
88 }
89
90 // TODO(skyostil): Add a separate work queue in case in case locking overhead
91 // becomes an issue.
92 bool has_next;
93 std::function<void()> immediate_task;
94 {
95 std::lock_guard<std::mutex> lock(lock_);
96 if (immediate_tasks_.empty())
97 return;
98 immediate_task = std::move(immediate_tasks_.front());
99 immediate_tasks_.pop_front();
100 has_next = !immediate_tasks_.empty();
101 }
102 // Do another pass through the event loop even if we have immediate tasks to
103 // run for fairness.
104 if (has_next)
105 ScheduleImmediateWakeUp();
106 errno = 0;
107 RunTask(immediate_task);
108 }
109
RunDelayedTask()110 void AndroidTaskRunner::RunDelayedTask() {
111 uint64_t unused = 0;
112 if (read(delayed_timer_.get(), &unused, sizeof(unused)) != sizeof(unused) &&
113 errno != EAGAIN) {
114 PERFETTO_DPLOG("read");
115 }
116
117 std::function<void()> delayed_task;
118 TimeMillis next_wake_up{};
119 {
120 std::lock_guard<std::mutex> lock(lock_);
121 if (delayed_tasks_.empty())
122 return;
123 auto it = delayed_tasks_.begin();
124 PERFETTO_DCHECK(!(GetWallTimeMs() < it->first));
125 delayed_task = std::move(it->second);
126 delayed_tasks_.erase(it);
127 if (!delayed_tasks_.empty())
128 next_wake_up = delayed_tasks_.begin()->first;
129 }
130 if (next_wake_up.count())
131 ScheduleDelayedWakeUp(next_wake_up);
132 errno = 0;
133 RunTask(delayed_task);
134 }
135
ScheduleImmediateWakeUp()136 void AndroidTaskRunner::ScheduleImmediateWakeUp() {
137 uint64_t value = 1;
138 if (write(immediate_event_.get(), &value, sizeof(value)) == -1 &&
139 errno != EAGAIN) {
140 PERFETTO_DPLOG("write");
141 }
142 }
143
ScheduleDelayedWakeUp(TimeMillis time)144 void AndroidTaskRunner::ScheduleDelayedWakeUp(TimeMillis time) {
145 PERFETTO_DCHECK(time.count());
146 struct itimerspec wake_up = {};
147 wake_up.it_value = ToPosixTimespec(time);
148 if (timerfd_settime(delayed_timer_.get(), TFD_TIMER_ABSTIME, &wake_up,
149 nullptr) == -1) {
150 PERFETTO_DPLOG("timerfd_settime");
151 }
152 }
153
PostTask(std::function<void ()> task)154 void AndroidTaskRunner::PostTask(std::function<void()> task) {
155 bool was_empty;
156 {
157 std::lock_guard<std::mutex> lock(lock_);
158 was_empty = immediate_tasks_.empty();
159 immediate_tasks_.push_back(std::move(task));
160 }
161 if (was_empty)
162 ScheduleImmediateWakeUp();
163 }
164
PostDelayedTask(std::function<void ()> task,uint32_t delay_ms)165 void AndroidTaskRunner::PostDelayedTask(std::function<void()> task,
166 uint32_t delay_ms) {
167 PERFETTO_DCHECK(delay_ms >= 0);
168 TimeMillis runtime = GetWallTimeMs() + TimeMillis(delay_ms);
169 bool is_next = false;
170 {
171 std::lock_guard<std::mutex> lock(lock_);
172 auto it = delayed_tasks_.insert(std::make_pair(runtime, std::move(task)));
173 if (it == delayed_tasks_.begin())
174 is_next = true;
175 }
176 if (is_next)
177 ScheduleDelayedWakeUp(runtime);
178 }
179
AddFileDescriptorWatch(int fd,std::function<void ()> task)180 void AndroidTaskRunner::AddFileDescriptorWatch(int fd,
181 std::function<void()> task) {
182 PERFETTO_DCHECK(fd >= 0);
183 {
184 std::lock_guard<std::mutex> lock(lock_);
185 PERFETTO_DCHECK(!watch_tasks_.count(fd));
186 watch_tasks_[fd] = std::move(task);
187 }
188 // It's safe for the callback to hang on to |this| as everything is
189 // unregistered in the destructor.
190 auto callback = [](int signalled_fd, int events, void* data) -> int {
191 AndroidTaskRunner* task_runner = reinterpret_cast<AndroidTaskRunner*>(data);
192 return task_runner->OnFileDescriptorEvent(signalled_fd, events) ? 1 : 0;
193 };
194 PERFETTO_CHECK(ALooper_addFd(looper_, fd, ALOOPER_POLL_CALLBACK,
195 ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR |
196 ALOOPER_EVENT_HANGUP,
197 std::move(callback), this) != -1);
198 }
199
OnFileDescriptorEvent(int signalled_fd,int events)200 bool AndroidTaskRunner::OnFileDescriptorEvent(int signalled_fd, int events) {
201 PERFETTO_DCHECK_THREAD(thread_checker_);
202 if (!(events & (ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR |
203 ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_INVALID))) {
204 return true;
205 }
206 std::function<void()> task;
207 {
208 std::lock_guard<std::mutex> lock(lock_);
209 auto it = watch_tasks_.find(signalled_fd);
210 if (it == watch_tasks_.end())
211 return false;
212 task = it->second;
213 }
214 errno = 0;
215 RunTask(task);
216 return true;
217 }
218
RemoveFileDescriptorWatch(int fd)219 void AndroidTaskRunner::RemoveFileDescriptorWatch(int fd) {
220 PERFETTO_DCHECK(fd >= 0);
221 {
222 std::lock_guard<std::mutex> lock(lock_);
223 PERFETTO_DCHECK(watch_tasks_.count(fd));
224 watch_tasks_.erase(fd);
225 }
226 ALooper_removeFd(looper_, fd);
227 }
228
229 } // namespace base
230 } // namespace perfetto
231