• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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