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