blob: eda9463636a78edaddb0c40cbe9ff62bedc299be [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
2**
3** Copyright 2006, Brian Swetland <swetland@frotz.net>
4**
Elliott Hughesaa245492015-08-03 10:38:08 -07005** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08008**
Elliott Hughesaa245492015-08-03 10:38:08 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080010**
Elliott Hughesaa245492015-08-03 10:38:08 -070011** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080015** limitations under the License.
16*/
17
Yabin Cuiaed3c612015-09-22 15:52:57 -070018#define TRACE_TAG FDEVENT
JP Abgrall408fa572011-03-16 15:57:42 -070019
Dan Albert33134262015-03-19 15:21:08 -070020#include "sysdeps.h"
21#include "fdevent.h"
22
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023#include <fcntl.h>
Josh Gaoded557f2018-06-18 14:55:27 -070024#include <inttypes.h>
Josh Gao5791e212018-03-16 14:25:42 -070025#include <stdint.h>
Dan Albert33134262015-03-19 15:21:08 -070026#include <stdlib.h>
27#include <string.h>
Dan Albert33134262015-03-19 15:21:08 -070028#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080029
Josh Gao022d4472016-02-10 14:49:00 -080030#include <atomic>
Josh Gaoe39ccd32018-02-23 14:37:07 -080031#include <deque>
Josh Gao4c936392017-05-03 14:10:39 -070032#include <functional>
Yabin Cuia1080162015-09-04 16:19:56 -070033#include <list>
Josh Gao4c936392017-05-03 14:10:39 -070034#include <mutex>
Josh Gao1a901182019-01-31 15:51:52 -080035#include <optional>
Yabin Cuia1080162015-09-04 16:19:56 -070036#include <unordered_map>
Josh Gaoc162c712019-01-25 15:30:25 -080037#include <utility>
38#include <variant>
Yabin Cuia1080162015-09-04 16:19:56 -070039#include <vector>
40
Josh Gao39c1f4b2018-10-05 17:09:07 -070041#include <android-base/chrono_utils.h>
42#include <android-base/file.h>
Elliott Hughes4f713192015-12-04 22:00:26 -080043#include <android-base/logging.h>
44#include <android-base/stringprintf.h>
Josh Gao4c936392017-05-03 14:10:39 -070045#include <android-base/thread_annotations.h>
Josh Gao5791e212018-03-16 14:25:42 -070046#include <android-base/threads.h>
Yabin Cuia1080162015-09-04 16:19:56 -070047
Dan Albertcc731cc2015-02-24 21:26:58 -080048#include "adb_io.h"
leozwangd3fc15f2014-07-29 12:50:02 -070049#include "adb_trace.h"
Josh Gao4c936392017-05-03 14:10:39 -070050#include "adb_unique_fd.h"
Yabin Cui6dfef252015-10-06 15:10:05 -070051#include "adb_utils.h"
Josh Gao39c1f4b2018-10-05 17:09:07 -070052#include "sysdeps/chrono.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080053
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080054#define FDE_EVENTMASK 0x00ff
55#define FDE_STATEMASK 0xff00
56
57#define FDE_ACTIVE 0x0100
58#define FDE_PENDING 0x0200
59#define FDE_CREATED 0x0400
60
Yabin Cuia1080162015-09-04 16:19:56 -070061static std::string dump_fde(const fdevent* fde) {
62 std::string state;
63 if (fde->state & FDE_ACTIVE) {
64 state += "A";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080065 }
Yabin Cuia1080162015-09-04 16:19:56 -070066 if (fde->state & FDE_PENDING) {
67 state += "P";
68 }
69 if (fde->state & FDE_CREATED) {
70 state += "C";
71 }
72 if (fde->state & FDE_READ) {
73 state += "R";
74 }
75 if (fde->state & FDE_WRITE) {
76 state += "W";
77 }
78 if (fde->state & FDE_ERROR) {
79 state += "E";
80 }
Josh Gaoded557f2018-06-18 14:55:27 -070081 return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
82 state.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080083}
84
Josh Gaoc2cf1212019-06-28 16:34:36 -070085struct PollNode {
86 fdevent* fde;
87 adb_pollfd pollfd;
88
89 explicit PollNode(fdevent* fde) : fde(fde) {
90 memset(&pollfd, 0, sizeof(pollfd));
91 pollfd.fd = fde->fd.get();
92
93#if defined(__linux__)
94 // Always enable POLLRDHUP, so the host server can take action when some clients disconnect.
95 // Then we can avoid leaving many sockets in CLOSE_WAIT state. See http://b/23314034.
96 pollfd.events = POLLRDHUP;
97#endif
98 }
99};
100
101struct fdevent_context_poll : public fdevent_context {
102 virtual ~fdevent_context_poll() = default;
103
104 virtual fdevent* Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) final;
105 virtual unique_fd Destroy(fdevent* fde) final;
106
107 virtual void Set(fdevent* fde, unsigned events) final;
108 virtual void Add(fdevent* fde, unsigned events) final;
109 virtual void Del(fdevent* fde, unsigned events) final;
110 virtual void SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) final;
111
112 virtual void Loop() final;
113
114 virtual void CheckMainThread() final;
115
116 virtual void Run(std::function<void()> fn) final;
117
118 virtual void TerminateLoop() final;
119 virtual size_t InstalledCount() final;
120 virtual void Reset() final;
121
122 // All operations to fdevent should happen only in the main thread.
123 // That's why we don't need a lock for fdevent.
124 std::unordered_map<int, PollNode> poll_node_map_;
125 std::list<fdevent*> pending_list_;
126 bool main_thread_valid_ = false;
127 uint64_t main_thread_id_ = 0;
128 uint64_t fdevent_id_ = 0;
129
130 bool run_needs_flush_ = false;
131 unique_fd run_queue_notify_fd_;
132 std::mutex run_queue_mutex_;
133 std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
134
135 std::atomic<bool> terminate_loop_ = false;
136};
137
138static fdevent_context* g_ambient_fdevent_context = new fdevent_context_poll();
139
140static fdevent_context* fdevent_get_ambient() {
141 return g_ambient_fdevent_context;
142}
143
144void fdevent_context_poll::CheckMainThread() {
145 if (main_thread_valid_) {
146 CHECK_EQ(main_thread_id_, android::base::GetThreadId());
147 }
148}
149
150fdevent* fdevent_context_poll::Create(unique_fd fd, std::variant<fd_func, fd_func2> func,
151 void* arg) {
152 CheckMainThread();
153 CHECK_GE(fd.get(), 0);
Josh Gao71f775a2018-05-14 11:14:33 -0700154
155 fdevent* fde = new fdevent();
Josh Gaoc2cf1212019-06-28 16:34:36 -0700156 fde->id = fdevent_id_++;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157 fde->state = FDE_ACTIVE;
Josh Gaoc2cf1212019-06-28 16:34:36 -0700158 fde->fd = std::move(fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800159 fde->func = func;
160 fde->arg = arg;
Josh Gaoc2cf1212019-06-28 16:34:36 -0700161 if (!set_file_block_mode(fde->fd, false)) {
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700162 // Here is not proper to handle the error. If it fails here, some error is
163 // likely to be detected by poll(), then we can let the callback function
164 // to handle it.
Josh Gaoc2cf1212019-06-28 16:34:36 -0700165 LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
Yabin Cuia1080162015-09-04 16:19:56 -0700166 }
Josh Gaoc2cf1212019-06-28 16:34:36 -0700167 auto pair = poll_node_map_.emplace(fde->fd.get(), PollNode(fde));
168 CHECK(pair.second) << "install existing fd " << fde->fd.get();
Josh Gao71f775a2018-05-14 11:14:33 -0700169
170 fde->state |= FDE_CREATED;
171 return fde;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800172}
173
Josh Gaoc2cf1212019-06-28 16:34:36 -0700174unique_fd fdevent_context_poll::Destroy(fdevent* fde) {
175 CheckMainThread();
Josh Gao2f6c2fa2018-09-20 17:38:55 -0700176 if (!fde) {
177 return {};
178 }
179
Josh Gao71f775a2018-05-14 11:14:33 -0700180 if (!(fde->state & FDE_CREATED)) {
181 LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
182 }
183
Josh Gao2f6c2fa2018-09-20 17:38:55 -0700184 unique_fd result = std::move(fde->fd);
Yabin Cuia1080162015-09-04 16:19:56 -0700185 if (fde->state & FDE_ACTIVE) {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700186 poll_node_map_.erase(result.get());
Josh Gao2f6c2fa2018-09-20 17:38:55 -0700187
Yabin Cuia1080162015-09-04 16:19:56 -0700188 if (fde->state & FDE_PENDING) {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700189 pending_list_.remove(fde);
Yabin Cuia1080162015-09-04 16:19:56 -0700190 }
Yabin Cuia1080162015-09-04 16:19:56 -0700191 fde->state = 0;
192 fde->events = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800193 }
Josh Gao71f775a2018-05-14 11:14:33 -0700194
195 delete fde;
Josh Gao2f6c2fa2018-09-20 17:38:55 -0700196 return result;
197}
198
Josh Gaoc2cf1212019-06-28 16:34:36 -0700199void fdevent_context_poll::Set(fdevent* fde, unsigned events) {
200 CheckMainThread();
201 events &= FDE_EVENTMASK;
202 if ((fde->state & FDE_EVENTMASK) == events) {
203 return;
204 }
205 CHECK(fde->state & FDE_ACTIVE);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800206
Josh Gaoc2cf1212019-06-28 16:34:36 -0700207 auto it = poll_node_map_.find(fde->fd.get());
208 CHECK(it != poll_node_map_.end());
Yabin Cuia1080162015-09-04 16:19:56 -0700209 PollNode& node = it->second;
210 if (events & FDE_READ) {
211 node.pollfd.events |= POLLIN;
212 } else {
213 node.pollfd.events &= ~POLLIN;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800214 }
215
Yabin Cuia1080162015-09-04 16:19:56 -0700216 if (events & FDE_WRITE) {
217 node.pollfd.events |= POLLOUT;
218 } else {
219 node.pollfd.events &= ~POLLOUT;
220 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800221 fde->state = (fde->state & FDE_STATEMASK) | events;
222
Spencer Low888a7482015-09-29 18:33:38 -0700223 D("fdevent_set: %s, events = %u", dump_fde(fde).c_str(), events);
Yabin Cuia1080162015-09-04 16:19:56 -0700224
Spencer Low888a7482015-09-29 18:33:38 -0700225 if (fde->state & FDE_PENDING) {
226 // If we are pending, make sure we don't signal an event that is no longer wanted.
227 fde->events &= events;
228 if (fde->events == 0) {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700229 pending_list_.remove(fde);
Spencer Low888a7482015-09-29 18:33:38 -0700230 fde->state &= ~FDE_PENDING;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800231 }
232 }
233}
234
Josh Gaoc2cf1212019-06-28 16:34:36 -0700235void fdevent_context_poll::Add(fdevent* fde, unsigned events) {
236 Set(fde, (fde->state & FDE_EVENTMASK) | events);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800237}
238
Josh Gaoc2cf1212019-06-28 16:34:36 -0700239void fdevent_context_poll::Del(fdevent* fde, unsigned events) {
Josh Gao1a901182019-01-31 15:51:52 -0800240 CHECK(!(events & FDE_TIMEOUT));
Josh Gaoc2cf1212019-06-28 16:34:36 -0700241 Set(fde, (fde->state & FDE_EVENTMASK) & ~events);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242}
243
Josh Gaoc2cf1212019-06-28 16:34:36 -0700244void fdevent_context_poll::SetTimeout(fdevent* fde,
245 std::optional<std::chrono::milliseconds> timeout) {
246 CheckMainThread();
Josh Gao1a901182019-01-31 15:51:52 -0800247 fde->timeout = timeout;
248 fde->last_active = std::chrono::steady_clock::now();
249}
250
Josh Gao3777d2e2016-02-16 17:34:53 -0800251static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
Yabin Cuia1080162015-09-04 16:19:56 -0700252 std::string result;
Elliott Hughes65fe2512015-10-07 15:59:35 -0700253 for (const auto& pollfd : pollfds) {
Yabin Cuia1080162015-09-04 16:19:56 -0700254 std::string op;
255 if (pollfd.events & POLLIN) {
256 op += "R";
257 }
258 if (pollfd.events & POLLOUT) {
259 op += "W";
260 }
261 android::base::StringAppendF(&result, " %d(%s)", pollfd.fd, op.c_str());
262 }
263 return result;
264}
265
Josh Gaoc2cf1212019-06-28 16:34:36 -0700266static std::optional<std::chrono::milliseconds> calculate_timeout(fdevent_context_poll* ctx) {
Josh Gao1a901182019-01-31 15:51:52 -0800267 std::optional<std::chrono::milliseconds> result = std::nullopt;
268 auto now = std::chrono::steady_clock::now();
Josh Gaoc2cf1212019-06-28 16:34:36 -0700269 ctx->CheckMainThread();
Josh Gao1a901182019-01-31 15:51:52 -0800270
Josh Gaoc2cf1212019-06-28 16:34:36 -0700271 for (const auto& [fd, pollnode] : ctx->poll_node_map_) {
Josh Gao1a901182019-01-31 15:51:52 -0800272 UNUSED(fd);
273 auto timeout_opt = pollnode.fde->timeout;
274 if (timeout_opt) {
275 auto deadline = pollnode.fde->last_active + *timeout_opt;
276 auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(deadline - now);
277 if (time_left < std::chrono::milliseconds::zero()) {
278 time_left = std::chrono::milliseconds::zero();
279 }
280
281 if (!result) {
282 result = time_left;
283 } else {
284 result = std::min(*result, time_left);
285 }
286 }
287 }
288
289 return result;
290}
291
Josh Gaoc2cf1212019-06-28 16:34:36 -0700292static void fdevent_process(fdevent_context_poll* ctx) {
Josh Gao3777d2e2016-02-16 17:34:53 -0800293 std::vector<adb_pollfd> pollfds;
Josh Gaoc2cf1212019-06-28 16:34:36 -0700294 for (const auto& pair : ctx->poll_node_map_) {
Elliott Hughes65fe2512015-10-07 15:59:35 -0700295 pollfds.push_back(pair.second.pollfd);
Yabin Cuia1080162015-09-04 16:19:56 -0700296 }
297 CHECK_GT(pollfds.size(), 0u);
298 D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
Josh Gao39c1f4b2018-10-05 17:09:07 -0700299
Josh Gaoc2cf1212019-06-28 16:34:36 -0700300 auto timeout = calculate_timeout(ctx);
Josh Gao1a901182019-01-31 15:51:52 -0800301 int timeout_ms;
302 if (!timeout) {
303 timeout_ms = -1;
304 } else {
305 timeout_ms = timeout->count();
306 }
307
308 int ret = adb_poll(&pollfds[0], pollfds.size(), timeout_ms);
Yabin Cuia1080162015-09-04 16:19:56 -0700309 if (ret == -1) {
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700310 PLOG(ERROR) << "poll(), ret = " << ret;
311 return;
Yabin Cuia1080162015-09-04 16:19:56 -0700312 }
Josh Gao1a901182019-01-31 15:51:52 -0800313
314 auto post_poll = std::chrono::steady_clock::now();
315
Elliott Hughes65fe2512015-10-07 15:59:35 -0700316 for (const auto& pollfd : pollfds) {
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700317 if (pollfd.revents != 0) {
318 D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
319 }
Yabin Cuia1080162015-09-04 16:19:56 -0700320 unsigned events = 0;
321 if (pollfd.revents & POLLIN) {
322 events |= FDE_READ;
323 }
324 if (pollfd.revents & POLLOUT) {
325 events |= FDE_WRITE;
326 }
327 if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
328 // We fake a read, as the rest of the code assumes that errors will
329 // be detected at that point.
330 events |= FDE_READ | FDE_ERROR;
331 }
Yabin Cuiaa77e222015-09-29 12:25:33 -0700332#if defined(__linux__)
333 if (pollfd.revents & POLLRDHUP) {
334 events |= FDE_READ | FDE_ERROR;
335 }
336#endif
Josh Gaoc2cf1212019-06-28 16:34:36 -0700337 auto it = ctx->poll_node_map_.find(pollfd.fd);
338 CHECK(it != ctx->poll_node_map_.end());
Josh Gao1a901182019-01-31 15:51:52 -0800339 fdevent* fde = it->second.fde;
340
341 if (events == 0) {
342 // Check for timeout.
343 if (fde->timeout) {
344 auto deadline = fde->last_active + *fde->timeout;
345 if (deadline < post_poll) {
346 events |= FDE_TIMEOUT;
347 }
348 }
349 }
350
Yabin Cuia1080162015-09-04 16:19:56 -0700351 if (events != 0) {
Josh Gao3b37fa22018-05-14 13:42:49 -0700352 CHECK_EQ(fde->fd.get(), pollfd.fd);
Yabin Cuia1080162015-09-04 16:19:56 -0700353 fde->events |= events;
Josh Gao1a901182019-01-31 15:51:52 -0800354 fde->last_active = post_poll;
Yabin Cuia1080162015-09-04 16:19:56 -0700355 D("%s got events %x", dump_fde(fde).c_str(), events);
356 fde->state |= FDE_PENDING;
Josh Gaoc2cf1212019-06-28 16:34:36 -0700357 ctx->pending_list_.push_back(fde);
Yabin Cuia1080162015-09-04 16:19:56 -0700358 }
359 }
360}
361
Josh Gaoc162c712019-01-25 15:30:25 -0800362template <class T>
363struct always_false : std::false_type {};
364
Josh Gao4c936392017-05-03 14:10:39 -0700365static void fdevent_call_fdfunc(fdevent* fde) {
Yabin Cuia1080162015-09-04 16:19:56 -0700366 unsigned events = fde->events;
367 fde->events = 0;
Spencer Low888a7482015-09-29 18:33:38 -0700368 CHECK(fde->state & FDE_PENDING);
Yabin Cuia1080162015-09-04 16:19:56 -0700369 fde->state &= (~FDE_PENDING);
370 D("fdevent_call_fdfunc %s", dump_fde(fde).c_str());
Josh Gaoc162c712019-01-25 15:30:25 -0800371 std::visit(
372 [&](auto&& f) {
373 using F = std::decay_t<decltype(f)>;
374 if constexpr (std::is_same_v<fd_func, F>) {
375 f(fde->fd.get(), events, fde->arg);
376 } else if constexpr (std::is_same_v<fd_func2, F>) {
377 f(fde, events, fde->arg);
378 } else {
379 static_assert(always_false<F>::value, "non-exhaustive visitor");
380 }
381 },
382 fde->func);
Yabin Cuia1080162015-09-04 16:19:56 -0700383}
384
Josh Gaoc2cf1212019-06-28 16:34:36 -0700385static void fdevent_run_flush(fdevent_context_poll* ctx) EXCLUDES(ctx->run_queue_mutex_) {
Josh Gaoe39ccd32018-02-23 14:37:07 -0800386 // We need to be careful around reentrancy here, since a function we call can queue up another
387 // function.
388 while (true) {
389 std::function<void()> fn;
390 {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700391 std::lock_guard<std::mutex> lock(ctx->run_queue_mutex_);
392 if (ctx->run_queue_.empty()) {
Josh Gaoe39ccd32018-02-23 14:37:07 -0800393 break;
394 }
Josh Gaoc2cf1212019-06-28 16:34:36 -0700395 fn = ctx->run_queue_.front();
396 ctx->run_queue_.pop_front();
Josh Gaoe39ccd32018-02-23 14:37:07 -0800397 }
398 fn();
Josh Gao4c936392017-05-03 14:10:39 -0700399 }
Josh Gao4c936392017-05-03 14:10:39 -0700400}
401
Josh Gaoc2cf1212019-06-28 16:34:36 -0700402static void fdevent_run_func(int fd, unsigned ev, void* data) {
Josh Gao4c936392017-05-03 14:10:39 -0700403 CHECK_GE(fd, 0);
404 CHECK(ev & FDE_READ);
405
Josh Gaoc2cf1212019-06-28 16:34:36 -0700406 bool* run_needs_flush = static_cast<bool*>(data);
Josh Gao4c936392017-05-03 14:10:39 -0700407 char buf[1024];
408
409 // Empty the fd.
410 if (adb_read(fd, buf, sizeof(buf)) == -1) {
411 PLOG(FATAL) << "failed to empty run queue notify fd";
412 }
413
Josh Gaofa30bf32018-03-29 16:23:43 -0700414 // Mark that we need to flush, and then run it at the end of fdevent_loop.
Josh Gaoc2cf1212019-06-28 16:34:36 -0700415 *run_needs_flush = true;
Josh Gao4c936392017-05-03 14:10:39 -0700416}
417
Josh Gaoc2cf1212019-06-28 16:34:36 -0700418static void fdevent_run_setup(fdevent_context_poll* ctx) {
Josh Gaoe39ccd32018-02-23 14:37:07 -0800419 {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700420 std::lock_guard<std::mutex> lock(ctx->run_queue_mutex_);
421 CHECK(ctx->run_queue_notify_fd_.get() == -1);
Josh Gaoe39ccd32018-02-23 14:37:07 -0800422 int s[2];
423 if (adb_socketpair(s) != 0) {
424 PLOG(FATAL) << "failed to create run queue notify socketpair";
425 }
Josh Gao4c936392017-05-03 14:10:39 -0700426
Josh Gao1222abc2018-03-19 15:19:45 -0700427 if (!set_file_block_mode(s[0], false) || !set_file_block_mode(s[1], false)) {
428 PLOG(FATAL) << "failed to make run queue notify socket nonblocking";
429 }
430
Josh Gaoc2cf1212019-06-28 16:34:36 -0700431 ctx->run_queue_notify_fd_.reset(s[0]);
432 fdevent* fde = ctx->Create(unique_fd(s[1]), fdevent_run_func, &ctx->run_needs_flush_);
Josh Gaoe39ccd32018-02-23 14:37:07 -0800433 CHECK(fde != nullptr);
Josh Gaoc2cf1212019-06-28 16:34:36 -0700434 ctx->Add(fde, FDE_READ);
Josh Gaoe39ccd32018-02-23 14:37:07 -0800435 }
Josh Gao4c936392017-05-03 14:10:39 -0700436
Josh Gaoc2cf1212019-06-28 16:34:36 -0700437 fdevent_run_flush(ctx);
Josh Gao4c936392017-05-03 14:10:39 -0700438}
439
Josh Gaoc2cf1212019-06-28 16:34:36 -0700440void fdevent_context_poll::Run(std::function<void()> fn) {
441 std::lock_guard<std::mutex> lock(run_queue_mutex_);
442 run_queue_.push_back(std::move(fn));
Josh Gao4c936392017-05-03 14:10:39 -0700443
444 // run_queue_notify_fd could still be -1 if we're called before fdevent has finished setting up.
445 // In that case, rely on the setup code to flush the queue without a notification being needed.
Josh Gaoc2cf1212019-06-28 16:34:36 -0700446 if (run_queue_notify_fd_ != -1) {
447 int rc = adb_write(run_queue_notify_fd_.get(), "", 1);
Josh Gao1222abc2018-03-19 15:19:45 -0700448
449 // It's possible that we get EAGAIN here, if lots of notifications came in while handling.
450 if (rc == 0) {
451 PLOG(FATAL) << "run queue notify fd was closed?";
452 } else if (rc == -1 && errno != EAGAIN) {
Josh Gao4c936392017-05-03 14:10:39 -0700453 PLOG(FATAL) << "failed to write to run queue notify fd";
454 }
455 }
456}
457
Josh Gaoc2cf1212019-06-28 16:34:36 -0700458static void fdevent_check_spin(fdevent_context_poll* ctx, uint64_t cycle) {
Josh Gao39c1f4b2018-10-05 17:09:07 -0700459 // Check to see if we're spinning because we forgot about an fdevent
460 // by keeping track of how long fdevents have been continuously pending.
461 struct SpinCheck {
462 fdevent* fde;
463 android::base::boot_clock::time_point timestamp;
464 uint64_t cycle;
465 };
Josh Gaoc2cf1212019-06-28 16:34:36 -0700466
467 // TODO: Move this into the base fdevent_context.
Josh Gao39c1f4b2018-10-05 17:09:07 -0700468 static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>();
469 static auto last_cycle = android::base::boot_clock::now();
470
471 auto now = android::base::boot_clock::now();
472 if (now - last_cycle > 10ms) {
473 // We're not spinning.
474 g_continuously_pending.clear();
475 last_cycle = now;
476 return;
477 }
478 last_cycle = now;
479
Josh Gaoc2cf1212019-06-28 16:34:36 -0700480 for (auto* fde : ctx->pending_list_) {
Josh Gao39c1f4b2018-10-05 17:09:07 -0700481 auto it = g_continuously_pending.find(fde->id);
482 if (it == g_continuously_pending.end()) {
483 g_continuously_pending[fde->id] =
484 SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle};
485 } else {
486 it->second.cycle = cycle;
487 }
488 }
489
490 for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) {
491 if (it->second.cycle != cycle) {
492 it = g_continuously_pending.erase(it);
493 } else {
494 // Use an absurdly long window, since all we really care about is
495 // getting a bugreport eventually.
496 if (now - it->second.timestamp > 300s) {
497 LOG(FATAL_WITHOUT_ABORT)
498 << "detected spin in fdevent: " << dump_fde(it->second.fde);
499#if defined(__linux__)
500 int fd = it->second.fde->fd.get();
501 std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
502 std::string path;
503 if (!android::base::Readlink(fd_path, &path)) {
504 PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed";
505 }
506 LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path;
507#endif
508 abort();
509 }
510 ++it;
511 }
512 }
513}
514
Josh Gaoc2cf1212019-06-28 16:34:36 -0700515void fdevent_context_poll::Loop() {
516 this->main_thread_id_ = android::base::GetThreadId();
517 this->main_thread_valid_ = true;
518 fdevent_run_setup(this);
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200519
Josh Gao39c1f4b2018-10-05 17:09:07 -0700520 uint64_t cycle = 0;
Elliott Hughesaa245492015-08-03 10:38:08 -0700521 while (true) {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700522 if (terminate_loop_) {
Josh Gao022d4472016-02-10 14:49:00 -0800523 return;
524 }
525
Yabin Cuia1080162015-09-04 16:19:56 -0700526 D("--- --- waiting for events");
JP Abgrall408fa572011-03-16 15:57:42 -0700527
Josh Gaoc2cf1212019-06-28 16:34:36 -0700528 fdevent_process(this);
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200529
Josh Gaoc2cf1212019-06-28 16:34:36 -0700530 fdevent_check_spin(this, cycle++);
Josh Gao39c1f4b2018-10-05 17:09:07 -0700531
Josh Gaoc2cf1212019-06-28 16:34:36 -0700532 while (!pending_list_.empty()) {
533 fdevent* fde = pending_list_.front();
534 pending_list_.pop_front();
JP Abgrall408fa572011-03-16 15:57:42 -0700535 fdevent_call_fdfunc(fde);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800536 }
Josh Gaofa30bf32018-03-29 16:23:43 -0700537
Josh Gaoc2cf1212019-06-28 16:34:36 -0700538 if (run_needs_flush_) {
539 fdevent_run_flush(this);
540 run_needs_flush_ = false;
Josh Gaofa30bf32018-03-29 16:23:43 -0700541 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800542 }
543}
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700544
Josh Gaoc2cf1212019-06-28 16:34:36 -0700545void fdevent_context_poll::TerminateLoop() {
546 terminate_loop_ = true;
547}
548
549size_t fdevent_context_poll::InstalledCount() {
550 return poll_node_map_.size();
551}
552
553void fdevent_context_poll::Reset() {
554 poll_node_map_.clear();
555 pending_list_.clear();
556
557 std::lock_guard<std::mutex> lock(run_queue_mutex_);
558 run_queue_notify_fd_.reset();
559 run_queue_.clear();
560
561 main_thread_valid_ = false;
562 terminate_loop_ = false;
563}
564
565fdevent* fdevent_create(int fd, fd_func func, void* arg) {
566 unique_fd ufd(fd);
567 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
568}
569
570fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
571 unique_fd ufd(fd);
572 return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
573}
574
575unique_fd fdevent_release(fdevent* fde) {
576 return fdevent_get_ambient()->Destroy(fde);
577}
578
579void fdevent_destroy(fdevent* fde) {
580 fdevent_get_ambient()->Destroy(fde);
581}
582
583void fdevent_set(fdevent* fde, unsigned events) {
584 fdevent_get_ambient()->Set(fde, events);
585}
586
587void fdevent_add(fdevent* fde, unsigned events) {
588 fdevent_get_ambient()->Add(fde, events);
589}
590
591void fdevent_del(fdevent* fde, unsigned events) {
592 fdevent_get_ambient()->Del(fde, events);
593}
594
595void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
596 fdevent_get_ambient()->SetTimeout(fde, timeout);
597}
598
599void fdevent_run_on_main_thread(std::function<void()> fn) {
600 fdevent_get_ambient()->Run(std::move(fn));
601}
602
603void fdevent_loop() {
604 fdevent_get_ambient()->Loop();
605}
606
607void check_main_thread() {
608 fdevent_get_ambient()->CheckMainThread();
609}
610
Josh Gao022d4472016-02-10 14:49:00 -0800611void fdevent_terminate_loop() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700612 fdevent_get_ambient()->TerminateLoop();
Josh Gao022d4472016-02-10 14:49:00 -0800613}
614
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700615size_t fdevent_installed_count() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700616 return fdevent_get_ambient()->InstalledCount();
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700617}
618
619void fdevent_reset() {
Josh Gaoc2cf1212019-06-28 16:34:36 -0700620 return fdevent_get_ambient()->Reset();
Yabin Cuic1b1f6f2015-09-15 16:27:09 -0700621}