• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     looper_thread_id_ = android::base::GetThreadId();
109 
110     std::vector<fdevent_event> fde_events;
111     std::unordered_map<fdevent*, fdevent_event*> event_map;
112     std::vector<epoll_event> epoll_events;
113 
114     while (true) {
115         if (terminate_loop_) {
116             break;
117         }
118 
119         if (epoll_events.size() < this->installed_fdevents_.size()) {
120             epoll_events.resize(this->installed_fdevents_.size());
121         }
122 
123         int rc = -1;
124         while (rc == -1) {
125             std::optional<std::chrono::milliseconds> timeout = CalculatePollDuration();
126             int timeout_ms;
127             if (!timeout) {
128                 timeout_ms = -1;
129             } else {
130                 timeout_ms = timeout->count();
131             }
132 
133             rc = epoll_wait(epoll_fd_.get(), epoll_events.data(), epoll_events.size(), timeout_ms);
134             if (rc == -1 && errno != EINTR) {
135                 PLOG(FATAL) << "epoll_wait failed";
136             }
137         }
138 
139         auto post_poll = std::chrono::steady_clock::now();
140         fde_events.reserve(installed_fdevents_.size());
141         fde_events.clear();
142         event_map.clear();
143 
144         for (int i = 0; i < rc; ++i) {
145             fdevent* fde = static_cast<fdevent*>(epoll_events[i].data.ptr);
146 
147             unsigned events = 0;
148             if (epoll_events[i].events & EPOLLIN) {
149                 CHECK(fde->state & FDE_READ);
150                 events |= FDE_READ;
151             }
152             if (epoll_events[i].events & EPOLLOUT) {
153                 CHECK(fde->state & FDE_WRITE);
154                 events |= FDE_WRITE;
155             }
156             if (epoll_events[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
157                 // We fake a read, as the rest of the code assumes that errors will
158                 // be detected at that point.
159                 events |= FDE_READ | FDE_ERROR;
160             }
161 
162             LOG(DEBUG) << dump_fde(fde) << " got events " << std::hex << std::showbase << events;
163             auto& fde_event = fde_events.emplace_back(fde, events);
164             event_map[fde] = &fde_event;
165             fde->last_active = post_poll;
166         }
167 
168         for (auto& [fd, fde] : installed_fdevents_) {
169             unsigned events = 0;
170             if (auto it = event_map.find(&fde); it != event_map.end()) {
171                 events = it->second->events;
172             }
173 
174             if (events == 0) {
175                 if (fde.timeout) {
176                     auto deadline = fde.last_active + *fde.timeout;
177                     if (deadline < post_poll) {
178                         events |= FDE_TIMEOUT;
179                         LOG(DEBUG) << dump_fde(&fde) << " timed out";
180                         fde_events.emplace_back(&fde, events);
181                         fde.last_active = post_poll;
182                     }
183                 }
184             }
185         }
186         this->HandleEvents(fde_events);
187         fde_events.clear();
188     }
189 
190     looper_thread_id_.reset();
191 }
192 
InstalledCount()193 size_t fdevent_context_epoll::InstalledCount() {
194     // We always have an installed fde for interrupt.
195     return this->installed_fdevents_.size() - 1;
196 }
197 
Interrupt()198 void fdevent_context_epoll::Interrupt() {
199     uint64_t i = 1;
200     ssize_t rc = TEMP_FAILURE_RETRY(adb_write(this->interrupt_fd_, &i, sizeof(i)));
201     if (rc != sizeof(i)) {
202         PLOG(FATAL) << "failed to write to fdevent interrupt eventfd";
203     }
204 }
205 
206 #endif  // defined(__linux__)
207