• 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/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