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 
fdevent_interrupt(int fd,unsigned,void *)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 
fdevent_context_epoll()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 
~fdevent_context_epoll()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 
calculate_epoll_event(fdevent * fde)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 
Register(fdevent * fde)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 
Unregister(fdevent * fde)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 
Set(fdevent * fde,unsigned events)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 
Loop()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 
InstalledCount()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 
Interrupt()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