blob: e20a295394cb45c1566e836d220ab95f131f618f [file] [log] [blame]
Josh Gao9e4aa3a2019-07-08 15:23:17 -07001/*
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 */
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020016
Yabin Cui19bec5b2015-09-22 15:52:57 -070017#define TRACE_TAG FDEVENT
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070018
Dan Albertdb6fe642015-03-19 15:21:08 -070019#include "sysdeps.h"
Dan Albertdb6fe642015-03-19 15:21:08 -070020
Josh Gao12937162018-06-18 14:55:27 -070021#include <inttypes.h>
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020022
Josh Gao83e435a2019-07-08 18:05:16 -070023#include <android-base/logging.h>
Elliott Hughesf55ead92015-12-04 22:00:26 -080024#include <android-base/stringprintf.h>
Josh Gao83e435a2019-07-08 18:05:16 -070025#include <android-base/threads.h>
Yabin Cui56112542015-09-04 16:19:56 -070026
Josh Gaoe10e56b2019-07-08 18:16:19 -070027#include "adb_utils.h"
Josh Gao9e4aa3a2019-07-08 15:23:17 -070028#include "fdevent.h"
Josh Gaodd716422019-07-11 13:47:44 -070029#include "fdevent_epoll.h"
Josh Gaod7c49ec2020-04-20 19:22:05 -070030
31#if !defined(__linux__)
Josh Gao9e4aa3a2019-07-08 15:23:17 -070032#include "fdevent_poll.h"
Josh Gaod7c49ec2020-04-20 19:22:05 -070033#endif
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020034
Josh Gao4729f462019-07-11 16:35:37 -070035using namespace std::chrono_literals;
36using std::chrono::duration_cast;
37
38void invoke_fde(struct fdevent* fde, unsigned events) {
39 if (auto f = std::get_if<fd_func>(&fde->func)) {
40 (*f)(fde->fd.get(), events, fde->arg);
41 } else if (auto f = std::get_if<fd_func2>(&fde->func)) {
42 (*f)(fde, events, fde->arg);
43 } else {
44 __builtin_unreachable();
45 }
46}
47
Josh Gao9e4aa3a2019-07-08 15:23:17 -070048std::string dump_fde(const fdevent* fde) {
Yabin Cui56112542015-09-04 16:19:56 -070049 std::string state;
Yabin Cui56112542015-09-04 16:19:56 -070050 if (fde->state & FDE_READ) {
51 state += "R";
52 }
53 if (fde->state & FDE_WRITE) {
54 state += "W";
55 }
56 if (fde->state & FDE_ERROR) {
57 state += "E";
58 }
Josh Gao12937162018-06-18 14:55:27 -070059 return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
60 state.c_str());
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020061}
62
Josh Gaoe10e56b2019-07-08 18:16:19 -070063fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) {
Shaju Mathew705fa1c2022-12-31 19:36:54 -080064 CheckLooperThread();
65
Josh Gaoe10e56b2019-07-08 18:16:19 -070066 CHECK_GE(fd.get(), 0);
67
Josh Gao4729f462019-07-11 16:35:37 -070068 int fd_num = fd.get();
69
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -070070 auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
71 CHECK(inserted);
72
73 fdevent* fde = &it->second;
Josh Gaoe10e56b2019-07-08 18:16:19 -070074 fde->id = fdevent_id_++;
Josh Gao4729f462019-07-11 16:35:37 -070075 fde->state = 0;
Josh Gaoe10e56b2019-07-08 18:16:19 -070076 fde->fd = std::move(fd);
77 fde->func = func;
78 fde->arg = arg;
79 if (!set_file_block_mode(fde->fd, false)) {
80 // Here is not proper to handle the error. If it fails here, some error is
81 // likely to be detected by poll(), then we can let the callback function
82 // to handle it.
83 LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
84 }
85
Colin Crosse6e73772023-04-20 11:54:52 -070086 this->fdevent_set_.insert(fde);
Josh Gaoe10e56b2019-07-08 18:16:19 -070087 this->Register(fde);
88 return fde;
89}
90
91unique_fd fdevent_context::Destroy(fdevent* fde) {
Shaju Mathew705fa1c2022-12-31 19:36:54 -080092 CheckLooperThread();
93
Josh Gaoe10e56b2019-07-08 18:16:19 -070094 if (!fde) {
95 return {};
96 }
97
98 this->Unregister(fde);
99
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700100 unique_fd fd = std::move(fde->fd);
101
102 auto erased = this->installed_fdevents_.erase(fd.get());
Josh Gao4729f462019-07-11 16:35:37 -0700103 CHECK_EQ(1UL, erased);
Colin Crosse6e73772023-04-20 11:54:52 -0700104 erased = this->fdevent_set_.erase(fde);
105 CHECK_EQ(1UL, erased);
Josh Gao4729f462019-07-11 16:35:37 -0700106
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700107 return fd;
Josh Gaoe10e56b2019-07-08 18:16:19 -0700108}
109
Josh Gaoad93dc52019-07-08 18:17:41 -0700110void fdevent_context::Add(fdevent* fde, unsigned events) {
Josh Gao4729f462019-07-11 16:35:37 -0700111 CHECK(!(events & FDE_TIMEOUT));
112 Set(fde, fde->state | events);
Josh Gaoad93dc52019-07-08 18:17:41 -0700113}
114
115void fdevent_context::Del(fdevent* fde, unsigned events) {
116 CHECK(!(events & FDE_TIMEOUT));
Josh Gao4729f462019-07-11 16:35:37 -0700117 Set(fde, fde->state & ~events);
Josh Gaoad93dc52019-07-08 18:17:41 -0700118}
119
120void fdevent_context::SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
Shaju Mathew705fa1c2022-12-31 19:36:54 -0800121 CheckLooperThread(); // Caller thread is expected to have already
122 // initialized the looper thread instance variable.
Josh Gaoad93dc52019-07-08 18:17:41 -0700123 fde->timeout = timeout;
124 fde->last_active = std::chrono::steady_clock::now();
125}
126
Josh Gao4729f462019-07-11 16:35:37 -0700127std::optional<std::chrono::milliseconds> fdevent_context::CalculatePollDuration() {
128 std::optional<std::chrono::milliseconds> result = std::nullopt;
129 auto now = std::chrono::steady_clock::now();
Shaju Mathew705fa1c2022-12-31 19:36:54 -0800130
131 CheckLooperThread();
Josh Gao4729f462019-07-11 16:35:37 -0700132
133 for (const auto& [fd, fde] : this->installed_fdevents_) {
134 UNUSED(fd);
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700135 auto timeout_opt = fde.timeout;
Josh Gao4729f462019-07-11 16:35:37 -0700136 if (timeout_opt) {
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700137 auto deadline = fde.last_active + *timeout_opt;
Josh Gao4729f462019-07-11 16:35:37 -0700138 auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
139 if (time_left < 0ms) {
140 time_left = 0ms;
141 }
142
143 if (!result) {
144 result = time_left;
145 } else {
146 result = std::min(*result, time_left);
147 }
148 }
149 }
150
151 return result;
152}
153
154void fdevent_context::HandleEvents(const std::vector<fdevent_event>& events) {
155 for (const auto& event : events) {
Colin Crosse6e73772023-04-20 11:54:52 -0700156 // Verify the fde is still installed before invoking it. It could have been unregistered
157 // and destroyed inside an earlier event handler.
158 if (this->fdevent_set_.find(event.fde) != this->fdevent_set_.end()) {
159 invoke_fde(event.fde, event.events);
160 break;
161 }
Josh Gao4729f462019-07-11 16:35:37 -0700162 }
163 FlushRunQueue();
164}
165
166void fdevent_context::FlushRunQueue() {
167 // We need to be careful around reentrancy here, since a function we call can queue up another
168 // function.
169 while (true) {
170 std::function<void()> fn;
171 {
172 std::lock_guard<std::mutex> lock(this->run_queue_mutex_);
173 if (this->run_queue_.empty()) {
174 break;
175 }
176 fn = std::move(this->run_queue_.front());
177 this->run_queue_.pop_front();
178 }
179 fn();
180 }
181}
182
Shaju Mathew705fa1c2022-12-31 19:36:54 -0800183void fdevent_context::CheckLooperThread() const {
184 if (looper_thread_id_) {
185 CHECK_EQ(*looper_thread_id_, android::base::GetThreadId());
Josh Gao83e435a2019-07-08 18:05:16 -0700186 }
187}
188
Josh Gaoc5e99e02019-07-08 17:37:23 -0700189void fdevent_context::Run(std::function<void()> fn) {
190 {
191 std::lock_guard<std::mutex> lock(run_queue_mutex_);
192 run_queue_.push_back(std::move(fn));
193 }
194
195 Interrupt();
196}
197
Josh Gaodf92f8a2019-07-08 18:08:06 -0700198void fdevent_context::TerminateLoop() {
199 terminate_loop_ = true;
200 Interrupt();
201}
202
Josh Gaodd716422019-07-11 13:47:44 -0700203static std::unique_ptr<fdevent_context> fdevent_create_context() {
204#if defined(__linux__)
205 return std::make_unique<fdevent_context_epoll>();
206#else
207 return std::make_unique<fdevent_context_poll>();
208#endif
209}
210
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700211static auto& g_ambient_fdevent_context() {
212 static auto context = fdevent_create_context().release();
213 return context;
214}
Josh Gaoc0810502019-06-28 16:34:36 -0700215
216static fdevent_context* fdevent_get_ambient() {
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700217 return g_ambient_fdevent_context();
Josh Gaoc0810502019-06-28 16:34:36 -0700218}
219
Josh Gaoc0810502019-06-28 16:34:36 -0700220fdevent* fdevent_create(int fd, fd_func func, void* arg) {
221 unique_fd ufd(fd);
222 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
223}
224
225fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
226 unique_fd ufd(fd);
227 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
228}
229
230unique_fd fdevent_release(fdevent* fde) {
231 return fdevent_get_ambient()->Destroy(fde);
232}
233
234void fdevent_destroy(fdevent* fde) {
235 fdevent_get_ambient()->Destroy(fde);
236}
237
238void fdevent_set(fdevent* fde, unsigned events) {
239 fdevent_get_ambient()->Set(fde, events);
240}
241
242void fdevent_add(fdevent* fde, unsigned events) {
243 fdevent_get_ambient()->Add(fde, events);
244}
245
246void fdevent_del(fdevent* fde, unsigned events) {
247 fdevent_get_ambient()->Del(fde, events);
248}
249
250void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
251 fdevent_get_ambient()->SetTimeout(fde, timeout);
252}
253
Shaju Mathew705fa1c2022-12-31 19:36:54 -0800254void fdevent_run_on_looper(std::function<void()> fn) {
Josh Gaoc0810502019-06-28 16:34:36 -0700255 fdevent_get_ambient()->Run(std::move(fn));
256}
257
258void fdevent_loop() {
259 fdevent_get_ambient()->Loop();
260}
261
Shaju Mathew705fa1c2022-12-31 19:36:54 -0800262void fdevent_check_looper() {
263 fdevent_get_ambient()->CheckLooperThread();
Josh Gaoc0810502019-06-28 16:34:36 -0700264}
265
Josh Gao511763b2016-02-10 14:49:00 -0800266void fdevent_terminate_loop() {
Josh Gaoc0810502019-06-28 16:34:36 -0700267 fdevent_get_ambient()->TerminateLoop();
Josh Gao511763b2016-02-10 14:49:00 -0800268}
269
Yabin Cui2ce9d562015-09-15 16:27:09 -0700270size_t fdevent_installed_count() {
Josh Gaoc0810502019-06-28 16:34:36 -0700271 return fdevent_get_ambient()->InstalledCount();
Yabin Cui2ce9d562015-09-15 16:27:09 -0700272}
273
274void fdevent_reset() {
Yurii Zubrytskyi22863bd2020-03-18 22:29:10 -0700275 auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
276 delete old;
Yabin Cui2ce9d562015-09-15 16:27:09 -0700277}