blob: 70cb9b3a6db46f51d2c8779d10d066f0aca5963c [file] [log] [blame]
Josh Gao95068bb2019-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 */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080016
Yabin Cuiaed3c612015-09-22 15:52:57 -070017#define TRACE_TAG FDEVENT
JP Abgrall408fa572011-03-16 15:57:42 -070018
Dan Albert33134262015-03-19 15:21:08 -070019#include "sysdeps.h"
Dan Albert33134262015-03-19 15:21:08 -070020
Josh Gaoded557f2018-06-18 14:55:27 -070021#include <inttypes.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080022
Josh Gao2c95bf72019-07-08 18:05:16 -070023#include <android-base/logging.h>
Elliott Hughes4f713192015-12-04 22:00:26 -080024#include <android-base/stringprintf.h>
Josh Gao2c95bf72019-07-08 18:05:16 -070025#include <android-base/threads.h>
Yabin Cuia1080162015-09-04 16:19:56 -070026
Josh Gao33944a22019-07-08 18:16:19 -070027#include "adb_utils.h"
Josh Gao95068bb2019-07-08 15:23:17 -070028#include "fdevent.h"
Josh Gaob43ad442019-07-11 13:47:44 -070029#include "fdevent_epoll.h"
Josh Gao073c8d22020-04-20 19:22:05 -070030
31#if !defined(__linux__)
Josh Gao95068bb2019-07-08 15:23:17 -070032#include "fdevent_poll.h"
Josh Gao073c8d22020-04-20 19:22:05 -070033#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034
Josh Gaoe22cb9f2019-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 Gao95068bb2019-07-08 15:23:17 -070048std::string dump_fde(const fdevent* fde) {
Yabin Cuia1080162015-09-04 16:19:56 -070049 std::string state;
Yabin Cuia1080162015-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 Gaoded557f2018-06-18 14:55:27 -070059 return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
60 state.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080061}
62
Josh Gao33944a22019-07-08 18:16:19 -070063fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) {
64 CheckMainThread();
65 CHECK_GE(fd.get(), 0);
66
Josh Gaoe22cb9f2019-07-11 16:35:37 -070067 int fd_num = fd.get();
68
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -070069 auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
70 CHECK(inserted);
71
72 fdevent* fde = &it->second;
Josh Gao33944a22019-07-08 18:16:19 -070073 fde->id = fdevent_id_++;
Josh Gaoe22cb9f2019-07-11 16:35:37 -070074 fde->state = 0;
Josh Gao33944a22019-07-08 18:16:19 -070075 fde->fd = std::move(fd);
76 fde->func = func;
77 fde->arg = arg;
78 if (!set_file_block_mode(fde->fd, false)) {
79 // Here is not proper to handle the error. If it fails here, some error is
80 // likely to be detected by poll(), then we can let the callback function
81 // to handle it.
82 LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
83 }
84
85 this->Register(fde);
86 return fde;
87}
88
89unique_fd fdevent_context::Destroy(fdevent* fde) {
90 CheckMainThread();
91 if (!fde) {
92 return {};
93 }
94
95 this->Unregister(fde);
96
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -070097 unique_fd fd = std::move(fde->fd);
98
99 auto erased = this->installed_fdevents_.erase(fd.get());
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700100 CHECK_EQ(1UL, erased);
101
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700102 return fd;
Josh Gao33944a22019-07-08 18:16:19 -0700103}
104
Josh Gao35b29362019-07-08 18:17:41 -0700105void fdevent_context::Add(fdevent* fde, unsigned events) {
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700106 CHECK(!(events & FDE_TIMEOUT));
107 Set(fde, fde->state | events);
Josh Gao35b29362019-07-08 18:17:41 -0700108}
109
110void fdevent_context::Del(fdevent* fde, unsigned events) {
111 CHECK(!(events & FDE_TIMEOUT));
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700112 Set(fde, fde->state & ~events);
Josh Gao35b29362019-07-08 18:17:41 -0700113}
114
115void fdevent_context::SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
116 CheckMainThread();
117 fde->timeout = timeout;
118 fde->last_active = std::chrono::steady_clock::now();
119}
120
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700121std::optional<std::chrono::milliseconds> fdevent_context::CalculatePollDuration() {
122 std::optional<std::chrono::milliseconds> result = std::nullopt;
123 auto now = std::chrono::steady_clock::now();
124 CheckMainThread();
125
126 for (const auto& [fd, fde] : this->installed_fdevents_) {
127 UNUSED(fd);
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700128 auto timeout_opt = fde.timeout;
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700129 if (timeout_opt) {
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700130 auto deadline = fde.last_active + *timeout_opt;
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700131 auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
132 if (time_left < 0ms) {
133 time_left = 0ms;
134 }
135
136 if (!result) {
137 result = time_left;
138 } else {
139 result = std::min(*result, time_left);
140 }
141 }
142 }
143
144 return result;
145}
146
147void fdevent_context::HandleEvents(const std::vector<fdevent_event>& events) {
148 for (const auto& event : events) {
149 invoke_fde(event.fde, event.events);
150 }
151 FlushRunQueue();
152}
153
154void fdevent_context::FlushRunQueue() {
155 // We need to be careful around reentrancy here, since a function we call can queue up another
156 // function.
157 while (true) {
158 std::function<void()> fn;
159 {
160 std::lock_guard<std::mutex> lock(this->run_queue_mutex_);
161 if (this->run_queue_.empty()) {
162 break;
163 }
164 fn = std::move(this->run_queue_.front());
165 this->run_queue_.pop_front();
166 }
167 fn();
168 }
169}
170
Josh Gao2c95bf72019-07-08 18:05:16 -0700171void fdevent_context::CheckMainThread() {
172 if (main_thread_id_) {
173 CHECK_EQ(*main_thread_id_, android::base::GetThreadId());
174 }
175}
176
Josh Gao95eef6b2019-07-08 17:37:23 -0700177void fdevent_context::Run(std::function<void()> fn) {
178 {
179 std::lock_guard<std::mutex> lock(run_queue_mutex_);
180 run_queue_.push_back(std::move(fn));
181 }
182
183 Interrupt();
184}
185
Josh Gaoebaa3482019-07-08 18:08:06 -0700186void fdevent_context::TerminateLoop() {
187 terminate_loop_ = true;
188 Interrupt();
189}
190
Josh Gaob43ad442019-07-11 13:47:44 -0700191static std::unique_ptr<fdevent_context> fdevent_create_context() {
192#if defined(__linux__)
193 return std::make_unique<fdevent_context_epoll>();
194#else
195 return std::make_unique<fdevent_context_poll>();
196#endif
197}
198
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700199static auto& g_ambient_fdevent_context() {
200 static auto context = fdevent_create_context().release();
201 return context;
202}
Josh Gaoc2cf1212019-06-28 16:34:36 -0700203
204static fdevent_context* fdevent_get_ambient() {
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700205 return g_ambient_fdevent_context();
Josh Gaoc2cf1212019-06-28 16:34:36 -0700206}
207
Josh Gaoc2cf1212019-06-28 16:34:36 -0700208fdevent* fdevent_create(int fd, fd_func func, void* arg) {
209 unique_fd ufd(fd);
210 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
211}
212
213fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
214 unique_fd ufd(fd);
215 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
216}
217
218unique_fd fdevent_release(fdevent* fde) {
219 return fdevent_get_ambient()->Destroy(fde);
220}
221
222void fdevent_destroy(fdevent* fde) {
223 fdevent_get_ambient()->Destroy(fde);
224}
225
226void fdevent_set(fdevent* fde, unsigned events) {
227 fdevent_get_ambient()->Set(fde, events);
228}
229
230void fdevent_add(fdevent* fde, unsigned events) {
231 fdevent_get_ambient()->Add(fde, events);
232}
233
234void fdevent_del(fdevent* fde, unsigned events) {
235 fdevent_get_ambient()->Del(fde, events);
236}
237
238void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
239 fdevent_get_ambient()->SetTimeout(fde, timeout);
240}
241
242void fdevent_run_on_main_thread(std::function<void()> fn) {
243 fdevent_get_ambient()->Run(std::move(fn));
244}
245
246void fdevent_loop() {
247 fdevent_get_ambient()->Loop();
248}
249
250void check_main_thread() {
251 fdevent_get_ambient()->CheckMainThread();
252}
253
Josh Gao022d4472016-02-10 14:49:00 -0800254void fdevent_terminate_loop() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700255 fdevent_get_ambient()->TerminateLoop();
Josh Gao022d4472016-02-10 14:49:00 -0800256}
257
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700258size_t fdevent_installed_count() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700259 return fdevent_get_ambient()->InstalledCount();
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700260}
261
262void fdevent_reset() {
Yurii Zubrytskyi4eb910e2020-03-18 22:29:10 -0700263 auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
264 delete old;
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700265}