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/timerfd.h>
21
22 namespace perfetto {
23 namespace base {
24
AndroidTaskRunner()25 AndroidTaskRunner::AndroidTaskRunner()
26 : looper_(ALooper_prepare(0 /* require callbacks */)),
27 delayed_timer_(
28 timerfd_create(kWallTimeClockSource, TFD_NONBLOCK | TFD_CLOEXEC)) {
29 ALooper_acquire(looper_);
30 PERFETTO_CHECK(delayed_timer_);
31 AddFileDescriptorWatch(immediate_event_.fd(),
32 std::bind(&AndroidTaskRunner::RunImmediateTask, this));
33 AddFileDescriptorWatch(delayed_timer_.get(),
34 std::bind(&AndroidTaskRunner::RunDelayedTask, this));
35 }
36
~AndroidTaskRunner()37 AndroidTaskRunner::~AndroidTaskRunner() {
38 PERFETTO_DCHECK_THREAD(thread_checker_);
39 std::lock_guard<std::mutex> lock(lock_);
40 for (const auto& watch : watch_tasks_) {
41 // ALooper doesn't guarantee that each watch doesn't run one last time if
42 // the file descriptor was already signalled. To guard against this point
43 // the watch to a no-op callback.
44 ALooper_addFd(
45 looper_, watch.first, ALOOPER_POLL_CALLBACK,
46 ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP,
47 [](int, int, void*) -> int { return 0; }, nullptr);
48 ALooper_removeFd(looper_, watch.first);
49 }
50 ALooper_release(looper_);
51
52 struct itimerspec time = {};
53 timerfd_settime(delayed_timer_.get(), TFD_TIMER_ABSTIME, &time, nullptr);
54 }
55
Run()56 void AndroidTaskRunner::Run() {
57 quit_ = false;
58 for (;;) {
59 {
60 std::lock_guard<std::mutex> lock(lock_);
61 if (quit_)
62 break;
63 }
64 ALooper_pollOnce(-1 /* timeout */, nullptr, nullptr, nullptr);
65 }
66 }
67
Quit()68 void AndroidTaskRunner::Quit() {
69 std::lock_guard<std::mutex> lock(lock_);
70 quit_ = true;
71 ALooper_wake(looper_);
72 }
73
IsIdleForTesting()74 bool AndroidTaskRunner::IsIdleForTesting() {
75 PERFETTO_DCHECK_THREAD(thread_checker_);
76 std::lock_guard<std::mutex> lock(lock_);
77 return immediate_tasks_.empty();
78 }
79
RunImmediateTask()80 void AndroidTaskRunner::RunImmediateTask() {
81 immediate_event_.Clear();
82
83 // If locking overhead becomes an issue, add a separate work queue.
84 bool has_next;
85 std::function<void()> immediate_task;
86 {
87 std::lock_guard<std::mutex> lock(lock_);
88 if (immediate_tasks_.empty())
89 return;
90 immediate_task = std::move(immediate_tasks_.front());
91 immediate_tasks_.pop_front();
92 has_next = !immediate_tasks_.empty();
93 }
94 // Do another pass through the event loop even if we have immediate tasks to
95 // run for fairness.
96 if (has_next)
97 ScheduleImmediateWakeUp();
98 errno = 0;
99 RunTask(immediate_task);
100 }
101
RunDelayedTask()102 void AndroidTaskRunner::RunDelayedTask() {
103 uint64_t unused = 0;
104 if (read(delayed_timer_.get(), &unused, sizeof(unused)) != sizeof(unused) &&
105 errno != EAGAIN) {
106 PERFETTO_DPLOG("read");
107 }
108
109 std::function<void()> delayed_task;
110 TimeMillis next_wake_up{};
111 {
112 std::lock_guard<std::mutex> lock(lock_);
113 if (delayed_tasks_.empty())
114 return;
115 auto it = delayed_tasks_.begin();
116 PERFETTO_DCHECK(GetWallTimeMs() >= it->first);
117 delayed_task = std::move(it->second);
118 delayed_tasks_.erase(it);
119 if (!delayed_tasks_.empty())
120 next_wake_up = delayed_tasks_.begin()->first;
121 }
122 if (next_wake_up.count())
123 ScheduleDelayedWakeUp(next_wake_up);
124 errno = 0;
125 RunTask(delayed_task);
126 }
127
ScheduleImmediateWakeUp()128 void AndroidTaskRunner::ScheduleImmediateWakeUp() {
129 immediate_event_.Notify();
130 }
131
ScheduleDelayedWakeUp(TimeMillis time)132 void AndroidTaskRunner::ScheduleDelayedWakeUp(TimeMillis time) {
133 PERFETTO_DCHECK(time.count());
134 struct itimerspec wake_up = {};
135 wake_up.it_value = ToPosixTimespec(time);
136 if (timerfd_settime(delayed_timer_.get(), TFD_TIMER_ABSTIME, &wake_up,
137 nullptr) == -1) {
138 PERFETTO_DPLOG("timerfd_settime");
139 }
140 }
141
PostTask(std::function<void ()> task)142 void AndroidTaskRunner::PostTask(std::function<void()> task) {
143 bool was_empty;
144 {
145 std::lock_guard<std::mutex> lock(lock_);
146 was_empty = immediate_tasks_.empty();
147 immediate_tasks_.push_back(std::move(task));
148 }
149 if (was_empty)
150 ScheduleImmediateWakeUp();
151 }
152
PostDelayedTask(std::function<void ()> task,uint32_t delay_ms)153 void AndroidTaskRunner::PostDelayedTask(std::function<void()> task,
154 uint32_t delay_ms) {
155 PERFETTO_DCHECK(delay_ms >= 0);
156 TimeMillis runtime = GetWallTimeMs() + TimeMillis(delay_ms);
157 bool is_next = false;
158 {
159 std::lock_guard<std::mutex> lock(lock_);
160 auto it = delayed_tasks_.insert(std::make_pair(runtime, std::move(task)));
161 if (it == delayed_tasks_.begin())
162 is_next = true;
163 }
164 if (is_next)
165 ScheduleDelayedWakeUp(runtime);
166 }
167
AddFileDescriptorWatch(int fd,std::function<void ()> task)168 void AndroidTaskRunner::AddFileDescriptorWatch(int fd,
169 std::function<void()> task) {
170 PERFETTO_DCHECK(fd >= 0);
171 {
172 std::lock_guard<std::mutex> lock(lock_);
173 PERFETTO_DCHECK(!watch_tasks_.count(fd));
174 watch_tasks_[fd] = std::move(task);
175 }
176 // It's safe for the callback to hang on to |this| as everything is
177 // unregistered in the destructor.
178 auto callback = [](int signalled_fd, int events, void* data) -> int {
179 AndroidTaskRunner* task_runner = reinterpret_cast<AndroidTaskRunner*>(data);
180 return task_runner->OnFileDescriptorEvent(signalled_fd, events) ? 1 : 0;
181 };
182 PERFETTO_CHECK(ALooper_addFd(looper_, fd, ALOOPER_POLL_CALLBACK,
183 ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR |
184 ALOOPER_EVENT_HANGUP,
185 std::move(callback), this) != -1);
186 }
187
OnFileDescriptorEvent(int signalled_fd,int events)188 bool AndroidTaskRunner::OnFileDescriptorEvent(int signalled_fd, int events) {
189 PERFETTO_DCHECK_THREAD(thread_checker_);
190 if (!(events & (ALOOPER_EVENT_INPUT | ALOOPER_EVENT_ERROR |
191 ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_INVALID))) {
192 return true;
193 }
194 std::function<void()> task;
195 {
196 std::lock_guard<std::mutex> lock(lock_);
197 auto it = watch_tasks_.find(signalled_fd);
198 if (it == watch_tasks_.end())
199 return false;
200 task = it->second;
201 }
202 errno = 0;
203 RunTask(task);
204 return true;
205 }
206
RemoveFileDescriptorWatch(int fd)207 void AndroidTaskRunner::RemoveFileDescriptorWatch(int fd) {
208 PERFETTO_DCHECK(fd >= 0);
209 {
210 std::lock_guard<std::mutex> lock(lock_);
211 PERFETTO_DCHECK(watch_tasks_.count(fd));
212 watch_tasks_.erase(fd);
213 }
214 ALooper_removeFd(looper_, fd);
215 }
216
RunsTasksOnCurrentThread() const217 bool AndroidTaskRunner::RunsTasksOnCurrentThread() const {
218 return looper_ == ALooper_forThread();
219 }
220
221 } // namespace base
222 } // namespace perfetto
223