Home | History | Annotate | Download | only in base
      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 
     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 
     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 
     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 
     71 void AndroidTaskRunner::Quit() {
     72   std::lock_guard<std::mutex> lock(lock_);
     73   quit_ = true;
     74   ALooper_wake(looper_);
     75 }
     76 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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