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