blob: d21521777e73baa7bcd27a8da296afdf146e6a53 [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"
29#include "fdevent_poll.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030
Josh Gaoe22cb9f2019-07-11 16:35:37 -070031using namespace std::chrono_literals;
32using std::chrono::duration_cast;
33
34void invoke_fde(struct fdevent* fde, unsigned events) {
35 if (auto f = std::get_if<fd_func>(&fde->func)) {
36 (*f)(fde->fd.get(), events, fde->arg);
37 } else if (auto f = std::get_if<fd_func2>(&fde->func)) {
38 (*f)(fde, events, fde->arg);
39 } else {
40 __builtin_unreachable();
41 }
42}
43
Josh Gao95068bb2019-07-08 15:23:17 -070044std::string dump_fde(const fdevent* fde) {
Yabin Cuia1080162015-09-04 16:19:56 -070045 std::string state;
Yabin Cuia1080162015-09-04 16:19:56 -070046 if (fde->state & FDE_READ) {
47 state += "R";
48 }
49 if (fde->state & FDE_WRITE) {
50 state += "W";
51 }
52 if (fde->state & FDE_ERROR) {
53 state += "E";
54 }
Josh Gaoded557f2018-06-18 14:55:27 -070055 return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
56 state.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057}
58
Josh Gao33944a22019-07-08 18:16:19 -070059fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) {
60 CheckMainThread();
61 CHECK_GE(fd.get(), 0);
62
Josh Gaoe22cb9f2019-07-11 16:35:37 -070063 int fd_num = fd.get();
64
Josh Gao33944a22019-07-08 18:16:19 -070065 fdevent* fde = new fdevent();
66 fde->id = fdevent_id_++;
Josh Gaoe22cb9f2019-07-11 16:35:37 -070067 fde->state = 0;
Josh Gao33944a22019-07-08 18:16:19 -070068 fde->fd = std::move(fd);
69 fde->func = func;
70 fde->arg = arg;
71 if (!set_file_block_mode(fde->fd, false)) {
72 // Here is not proper to handle the error. If it fails here, some error is
73 // likely to be detected by poll(), then we can let the callback function
74 // to handle it.
75 LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
76 }
77
Josh Gaoe22cb9f2019-07-11 16:35:37 -070078 auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fde);
79 CHECK(inserted);
80 UNUSED(it);
81
Josh Gao33944a22019-07-08 18:16:19 -070082 this->Register(fde);
83 return fde;
84}
85
86unique_fd fdevent_context::Destroy(fdevent* fde) {
87 CheckMainThread();
88 if (!fde) {
89 return {};
90 }
91
92 this->Unregister(fde);
93
Josh Gaoe22cb9f2019-07-11 16:35:37 -070094 auto erased = this->installed_fdevents_.erase(fde->fd.get());
95 CHECK_EQ(1UL, erased);
96
Josh Gao33944a22019-07-08 18:16:19 -070097 unique_fd result = std::move(fde->fd);
98 delete fde;
99 return result;
100}
101
Josh Gao35b29362019-07-08 18:17:41 -0700102void fdevent_context::Add(fdevent* fde, unsigned events) {
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700103 CHECK(!(events & FDE_TIMEOUT));
104 Set(fde, fde->state | events);
Josh Gao35b29362019-07-08 18:17:41 -0700105}
106
107void fdevent_context::Del(fdevent* fde, unsigned events) {
108 CHECK(!(events & FDE_TIMEOUT));
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700109 Set(fde, fde->state & ~events);
Josh Gao35b29362019-07-08 18:17:41 -0700110}
111
112void 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
Josh Gaoe22cb9f2019-07-11 16:35:37 -0700118std::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
144void 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
151void 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
Josh Gao2c95bf72019-07-08 18:05:16 -0700168void fdevent_context::CheckMainThread() {
169 if (main_thread_id_) {
170 CHECK_EQ(*main_thread_id_, android::base::GetThreadId());
171 }
172}
173
Josh Gao95eef6b2019-07-08 17:37:23 -0700174void 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
Josh Gaoebaa3482019-07-08 18:08:06 -0700183void fdevent_context::TerminateLoop() {
184 terminate_loop_ = true;
185 Interrupt();
186}
187
Josh Gao7adca932019-07-08 17:31:47 -0700188static auto& g_ambient_fdevent_context =
189 *new std::unique_ptr<fdevent_context>(new fdevent_context_poll());
Josh Gaoc2cf1212019-06-28 16:34:36 -0700190
191static fdevent_context* fdevent_get_ambient() {
Josh Gao7adca932019-07-08 17:31:47 -0700192 return g_ambient_fdevent_context.get();
Josh Gaoc2cf1212019-06-28 16:34:36 -0700193}
194
Josh Gaoc2cf1212019-06-28 16:34:36 -0700195fdevent* fdevent_create(int fd, fd_func func, void* arg) {
196 unique_fd ufd(fd);
197 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
198}
199
200fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
201 unique_fd ufd(fd);
202 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
203}
204
205unique_fd fdevent_release(fdevent* fde) {
206 return fdevent_get_ambient()->Destroy(fde);
207}
208
209void fdevent_destroy(fdevent* fde) {
210 fdevent_get_ambient()->Destroy(fde);
211}
212
213void fdevent_set(fdevent* fde, unsigned events) {
214 fdevent_get_ambient()->Set(fde, events);
215}
216
217void fdevent_add(fdevent* fde, unsigned events) {
218 fdevent_get_ambient()->Add(fde, events);
219}
220
221void fdevent_del(fdevent* fde, unsigned events) {
222 fdevent_get_ambient()->Del(fde, events);
223}
224
225void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
226 fdevent_get_ambient()->SetTimeout(fde, timeout);
227}
228
229void fdevent_run_on_main_thread(std::function<void()> fn) {
230 fdevent_get_ambient()->Run(std::move(fn));
231}
232
233void fdevent_loop() {
234 fdevent_get_ambient()->Loop();
235}
236
237void check_main_thread() {
238 fdevent_get_ambient()->CheckMainThread();
239}
240
Josh Gao022d4472016-02-10 14:49:00 -0800241void fdevent_terminate_loop() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700242 fdevent_get_ambient()->TerminateLoop();
Josh Gao022d4472016-02-10 14:49:00 -0800243}
244
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700245size_t fdevent_installed_count() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700246 return fdevent_get_ambient()->InstalledCount();
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700247}
248
249void fdevent_reset() {
Josh Gao7adca932019-07-08 17:31:47 -0700250 g_ambient_fdevent_context.reset(new fdevent_context_poll());
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700251}