1 /* 2 * Copyright (C) 2019 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 "fdevent_epoll.h" 18 19 #if defined(__linux__) 20 21 #include <sys/epoll.h> 22 #include <sys/eventfd.h> 23 24 #include <android-base/logging.h> 25 #include <android-base/threads.h> 26 27 #include "adb_unique_fd.h" 28 #include "fdevent.h" 29 30 static void fdevent_interrupt(int fd, unsigned, void*) { 31 uint64_t buf; 32 ssize_t rc = TEMP_FAILURE_RETRY(adb_read(fd, &buf, sizeof(buf))); 33 if (rc == -1) { 34 PLOG(FATAL) << "failed to read from fdevent interrupt fd"; 35 } 36 } 37 38 fdevent_context_epoll::fdevent_context_epoll() { 39 epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); 40 41 unique_fd interrupt_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); 42 if (interrupt_fd == -1) { 43 PLOG(FATAL) << "failed to create fdevent interrupt eventfd"; 44 } 45 46 unique_fd interrupt_fd_dup(fcntl(interrupt_fd.get(), F_DUPFD_CLOEXEC, 3)); 47 if (interrupt_fd_dup == -1) { 48 PLOG(FATAL) << "failed to dup fdevent interrupt eventfd"; 49 } 50 51 this->interrupt_fd_ = std::move(interrupt_fd_dup); 52 fdevent* fde = this->Create(std::move(interrupt_fd), fdevent_interrupt, nullptr); 53 CHECK(fde != nullptr); 54 this->Add(fde, FDE_READ); 55 } 56 57 fdevent_context_epoll::~fdevent_context_epoll() { 58 // Destroy calls virtual methods, but this class is final, so that's okay. 59 this->Destroy(this->interrupt_fde_); 60 } 61 62 static epoll_event calculate_epoll_event(fdevent* fde) { 63 epoll_event result; 64 result.events = 0; 65 if (fde->state & FDE_READ) { 66 result.events |= EPOLLIN; 67 } 68 if (fde->state & FDE_WRITE) { 69 result.events |= EPOLLOUT; 70 } 71 if (fde->state & FDE_ERROR) { 72 result.events |= EPOLLERR; 73 } 74 result.events |= EPOLLRDHUP; 75 result.data.ptr = fde; 76 return result; 77 } 78 79 void fdevent_context_epoll::Register(fdevent* fde) { 80 epoll_event ev = calculate_epoll_event(fde); 81 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, fde->fd.get(), &ev) != 0) { 82 PLOG(FATAL) << "failed to register fd " << fde->fd.get() << " with epoll"; 83 } 84 } 85 86 void fdevent_context_epoll::Unregister(fdevent* fde) { 87 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, fde->fd.get(), nullptr) != 0) { 88 PLOG(FATAL) << "failed to unregister fd " << fde->fd.get() << " with epoll"; 89 } 90 } 91 92 void fdevent_context_epoll::Set(fdevent* fde, unsigned events) { 93 unsigned previous_state = fde->state; 94 fde->state = events; 95 96 // If the state is the same, or only differed by FDE_TIMEOUT, we don't need to modify epoll. 97 if ((previous_state & ~FDE_TIMEOUT) == (events & ~FDE_TIMEOUT)) { 98 return; 99 } 100 101 epoll_event ev = calculate_epoll_event(fde); 102 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, fde->fd.get(), &ev) != 0) { 103 PLOG(FATAL) << "failed to modify fd " << fde->fd.get() << " with epoll"; 104 } 105 } 106 107 void fdevent_context_epoll::Loop() { 108 main_thread_id_ = android::base::GetThreadId(); 109 110 std::vector<fdevent_event> fde_events; 111 std::vector<epoll_event> epoll_events; 112 epoll_events.resize(this->installed_fdevents_.size()); 113 114 while (true) { 115 if (terminate_loop_) { 116 break; 117 } 118 119 int rc = -1; 120 while (rc == -1) { 121 std::optional<std::chrono::milliseconds> timeout = CalculatePollDuration(); 122 int timeout_ms; 123 if (!timeout) { 124 timeout_ms = -1; 125 } else { 126 timeout_ms = timeout->count(); 127 } 128 129 rc = epoll_wait(epoll_fd_.get(), epoll_events.data(), epoll_events.size(), timeout_ms); 130 if (rc == -1 && errno != EINTR) { 131 PLOG(FATAL) << "epoll_wait failed"; 132 } 133 } 134 135 auto post_poll = std::chrono::steady_clock::now(); 136 std::unordered_map<fdevent*, unsigned> event_map; 137 for (int i = 0; i < rc; ++i) { 138 fdevent* fde = static_cast<fdevent*>(epoll_events[i].data.ptr); 139 140 unsigned events = 0; 141 if (epoll_events[i].events & EPOLLIN) { 142 CHECK(fde->state & FDE_READ); 143 events |= FDE_READ; 144 } 145 if (epoll_events[i].events & EPOLLOUT) { 146 CHECK(fde->state & FDE_WRITE); 147 events |= FDE_WRITE; 148 } 149 if (epoll_events[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) { 150 // We fake a read, as the rest of the code assumes that errors will 151 // be detected at that point. 152 events |= FDE_READ | FDE_ERROR; 153 } 154 155 event_map[fde] = events; 156 } 157 158 for (auto& [fd, fde] : installed_fdevents_) { 159 unsigned events = 0; 160 if (auto it = event_map.find(&fde); it != event_map.end()) { 161 events = it->second; 162 } 163 164 if (events == 0) { 165 if (fde.timeout) { 166 auto deadline = fde.last_active + *fde.timeout; 167 if (deadline < post_poll) { 168 events |= FDE_TIMEOUT; 169 } 170 } 171 } 172 173 if (events != 0) { 174 LOG(DEBUG) << dump_fde(&fde) << " got events " << std::hex << std::showbase 175 << events; 176 fde_events.push_back({&fde, events}); 177 fde.last_active = post_poll; 178 } 179 } 180 this->HandleEvents(fde_events); 181 fde_events.clear(); 182 } 183 184 main_thread_id_.reset(); 185 } 186 187 size_t fdevent_context_epoll::InstalledCount() { 188 // We always have an installed fde for interrupt. 189 return this->installed_fdevents_.size() - 1; 190 } 191 192 void fdevent_context_epoll::Interrupt() { 193 uint64_t i = 1; 194 ssize_t rc = TEMP_FAILURE_RETRY(adb_write(this->interrupt_fd_, &i, sizeof(i))); 195 if (rc != sizeof(i)) { 196 PLOG(FATAL) << "failed to write to fdevent interrupt eventfd"; 197 } 198 } 199 200 #endif // defined(__linux__) 201