• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006, Brian Swetland <swetland@frotz.net>
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 #define TRACE_TAG FDEVENT
18 
19 #include "sysdeps.h"
20 
21 #include <inttypes.h>
22 
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/threads.h>
26 
27 #include "adb_utils.h"
28 #include "fdevent.h"
29 #include "fdevent_epoll.h"
30 #include "fdevent_poll.h"
31 
32 using namespace std::chrono_literals;
33 using std::chrono::duration_cast;
34 
invoke_fde(struct fdevent * fde,unsigned events)35 void invoke_fde(struct fdevent* fde, unsigned events) {
36     if (auto f = std::get_if<fd_func>(&fde->func)) {
37         (*f)(fde->fd.get(), events, fde->arg);
38     } else if (auto f = std::get_if<fd_func2>(&fde->func)) {
39         (*f)(fde, events, fde->arg);
40     } else {
41         __builtin_unreachable();
42     }
43 }
44 
dump_fde(const fdevent * fde)45 std::string dump_fde(const fdevent* fde) {
46     std::string state;
47     if (fde->state & FDE_READ) {
48         state += "R";
49     }
50     if (fde->state & FDE_WRITE) {
51         state += "W";
52     }
53     if (fde->state & FDE_ERROR) {
54         state += "E";
55     }
56     return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
57                                        state.c_str());
58 }
59 
Create(unique_fd fd,std::variant<fd_func,fd_func2> func,void * arg)60 fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) {
61     CheckMainThread();
62     CHECK_GE(fd.get(), 0);
63 
64     int fd_num = fd.get();
65 
66     auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
67     CHECK(inserted);
68 
69     fdevent* fde = &it->second;
70     fde->id = fdevent_id_++;
71     fde->state = 0;
72     fde->fd = std::move(fd);
73     fde->func = func;
74     fde->arg = arg;
75     if (!set_file_block_mode(fde->fd, false)) {
76         // Here is not proper to handle the error. If it fails here, some error is
77         // likely to be detected by poll(), then we can let the callback function
78         // to handle it.
79         LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
80     }
81 
82     this->Register(fde);
83     return fde;
84 }
85 
Destroy(fdevent * fde)86 unique_fd fdevent_context::Destroy(fdevent* fde) {
87     CheckMainThread();
88     if (!fde) {
89         return {};
90     }
91 
92     this->Unregister(fde);
93 
94     unique_fd fd = std::move(fde->fd);
95 
96     auto erased = this->installed_fdevents_.erase(fd.get());
97     CHECK_EQ(1UL, erased);
98 
99     return fd;
100 }
101 
Add(fdevent * fde,unsigned events)102 void fdevent_context::Add(fdevent* fde, unsigned events) {
103     CHECK(!(events & FDE_TIMEOUT));
104     Set(fde, fde->state | events);
105 }
106 
Del(fdevent * fde,unsigned events)107 void fdevent_context::Del(fdevent* fde, unsigned events) {
108     CHECK(!(events & FDE_TIMEOUT));
109     Set(fde, fde->state & ~events);
110 }
111 
SetTimeout(fdevent * fde,std::optional<std::chrono::milliseconds> timeout)112 void fdevent_context::SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
113     CheckMainThread();
114     fde->timeout = timeout;
115     fde->last_active = std::chrono::steady_clock::now();
116 }
117 
CalculatePollDuration()118 std::optional<std::chrono::milliseconds> fdevent_context::CalculatePollDuration() {
119     std::optional<std::chrono::milliseconds> result = std::nullopt;
120     auto now = std::chrono::steady_clock::now();
121     CheckMainThread();
122 
123     for (const auto& [fd, fde] : this->installed_fdevents_) {
124         UNUSED(fd);
125         auto timeout_opt = fde.timeout;
126         if (timeout_opt) {
127             auto deadline = fde.last_active + *timeout_opt;
128             auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
129             if (time_left < 0ms) {
130                 time_left = 0ms;
131             }
132 
133             if (!result) {
134                 result = time_left;
135             } else {
136                 result = std::min(*result, time_left);
137             }
138         }
139     }
140 
141     return result;
142 }
143 
HandleEvents(const std::vector<fdevent_event> & events)144 void fdevent_context::HandleEvents(const std::vector<fdevent_event>& events) {
145     for (const auto& event : events) {
146         invoke_fde(event.fde, event.events);
147     }
148     FlushRunQueue();
149 }
150 
FlushRunQueue()151 void fdevent_context::FlushRunQueue() {
152     // We need to be careful around reentrancy here, since a function we call can queue up another
153     // function.
154     while (true) {
155         std::function<void()> fn;
156         {
157             std::lock_guard<std::mutex> lock(this->run_queue_mutex_);
158             if (this->run_queue_.empty()) {
159                 break;
160             }
161             fn = std::move(this->run_queue_.front());
162             this->run_queue_.pop_front();
163         }
164         fn();
165     }
166 }
167 
CheckMainThread()168 void fdevent_context::CheckMainThread() {
169     if (main_thread_id_) {
170         CHECK_EQ(*main_thread_id_, android::base::GetThreadId());
171     }
172 }
173 
Run(std::function<void ()> fn)174 void fdevent_context::Run(std::function<void()> fn) {
175     {
176         std::lock_guard<std::mutex> lock(run_queue_mutex_);
177         run_queue_.push_back(std::move(fn));
178     }
179 
180     Interrupt();
181 }
182 
TerminateLoop()183 void fdevent_context::TerminateLoop() {
184     terminate_loop_ = true;
185     Interrupt();
186 }
187 
fdevent_create_context()188 static std::unique_ptr<fdevent_context> fdevent_create_context() {
189 #if defined(__linux__)
190     return std::make_unique<fdevent_context_epoll>();
191 #else
192     return std::make_unique<fdevent_context_poll>();
193 #endif
194 }
195 
g_ambient_fdevent_context()196 static auto& g_ambient_fdevent_context() {
197     static auto context = fdevent_create_context().release();
198     return context;
199 }
200 
fdevent_get_ambient()201 static fdevent_context* fdevent_get_ambient() {
202     return g_ambient_fdevent_context();
203 }
204 
fdevent_create(int fd,fd_func func,void * arg)205 fdevent* fdevent_create(int fd, fd_func func, void* arg) {
206     unique_fd ufd(fd);
207     return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
208 }
209 
fdevent_create(int fd,fd_func2 func,void * arg)210 fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
211     unique_fd ufd(fd);
212     return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
213 }
214 
fdevent_release(fdevent * fde)215 unique_fd fdevent_release(fdevent* fde) {
216     return fdevent_get_ambient()->Destroy(fde);
217 }
218 
fdevent_destroy(fdevent * fde)219 void fdevent_destroy(fdevent* fde) {
220     fdevent_get_ambient()->Destroy(fde);
221 }
222 
fdevent_set(fdevent * fde,unsigned events)223 void fdevent_set(fdevent* fde, unsigned events) {
224     fdevent_get_ambient()->Set(fde, events);
225 }
226 
fdevent_add(fdevent * fde,unsigned events)227 void fdevent_add(fdevent* fde, unsigned events) {
228     fdevent_get_ambient()->Add(fde, events);
229 }
230 
fdevent_del(fdevent * fde,unsigned events)231 void fdevent_del(fdevent* fde, unsigned events) {
232     fdevent_get_ambient()->Del(fde, events);
233 }
234 
fdevent_set_timeout(fdevent * fde,std::optional<std::chrono::milliseconds> timeout)235 void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
236     fdevent_get_ambient()->SetTimeout(fde, timeout);
237 }
238 
fdevent_run_on_main_thread(std::function<void ()> fn)239 void fdevent_run_on_main_thread(std::function<void()> fn) {
240     fdevent_get_ambient()->Run(std::move(fn));
241 }
242 
fdevent_loop()243 void fdevent_loop() {
244     fdevent_get_ambient()->Loop();
245 }
246 
check_main_thread()247 void check_main_thread() {
248     fdevent_get_ambient()->CheckMainThread();
249 }
250 
fdevent_terminate_loop()251 void fdevent_terminate_loop() {
252     fdevent_get_ambient()->TerminateLoop();
253 }
254 
fdevent_installed_count()255 size_t fdevent_installed_count() {
256     return fdevent_get_ambient()->InstalledCount();
257 }
258 
fdevent_reset()259 void fdevent_reset() {
260     auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
261     delete old;
262 }
263