blob: bd0f3b26e4e81ffa7895895f175da0a55905476d [file] [log] [blame]
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +02001/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
2**
3** Copyright 2006, Brian Swetland <swetland@frotz.net>
4**
JP Abgrall1f501f32011-02-23 18:44:39 -08005** 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
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +02008**
JP Abgrall1f501f32011-02-23 18:44:39 -08009** http://www.apache.org/licenses/LICENSE-2.0
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020010**
JP Abgrall1f501f32011-02-23 18:44:39 -080011** 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
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020015** limitations under the License.
16*/
17
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070018#include <sys/ioctl.h>
19
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020020#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24#include <errno.h>
25
26#include <fcntl.h>
27
28#include <stdarg.h>
29#include <stddef.h>
30
leozwangf25a6a42014-07-29 12:50:02 -070031#include "adb_trace.h"
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020032#include "fdevent.h"
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070033#include "transport.h"
34#include "sysdeps.h"
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020035
leozwangf25a6a42014-07-29 12:50:02 -070036#define TRACE_TAG TRACE_FDEVENT
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020037
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070038/* !!! Do not enable DEBUG for the adb that will run as the server:
39** both stdout and stderr are used to communicate between the client
40** and server. Any extra output will cause failures.
41*/
42#define DEBUG 0 /* non-0 will break adb server */
43
44// This socket is used when a subproc shell service exists.
45// It wakes up the fdevent_loop() and cause the correct handling
46// of the shell's pseudo-tty master. I.e. force close it.
47int SHELL_EXIT_NOTIFY_FD = -1;
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020048
49static void fatal(const char *fn, const char *fmt, ...)
50{
51 va_list ap;
52 va_start(ap, fmt);
53 fprintf(stderr, "%s:", fn);
54 vfprintf(stderr, fmt, ap);
55 va_end(ap);
56 abort();
57}
58
59#define FATAL(x...) fatal(__FUNCTION__, x)
60
61#if DEBUG
62static void dump_fde(fdevent *fde, const char *info)
63{
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070064 adb_mutex_lock(&D_lock);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020065 fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
66 fde->state & FDE_READ ? 'R' : ' ',
67 fde->state & FDE_WRITE ? 'W' : ' ',
68 fde->state & FDE_ERROR ? 'E' : ' ',
69 info);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070070 adb_mutex_unlock(&D_lock);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020071}
72#else
73#define dump_fde(fde, info) do { } while(0)
74#endif
75
76#define FDE_EVENTMASK 0x00ff
77#define FDE_STATEMASK 0xff00
78
79#define FDE_ACTIVE 0x0100
80#define FDE_PENDING 0x0200
81#define FDE_CREATED 0x0400
82
83static void fdevent_plist_enqueue(fdevent *node);
84static void fdevent_plist_remove(fdevent *node);
85static fdevent *fdevent_plist_dequeue(void);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -070086static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020087
88static fdevent list_pending = {
89 .next = &list_pending,
90 .prev = &list_pending,
Dan Albertbbbbea62014-11-24 23:34:35 -080091 .fd = -1,
92 .force_eof = 0,
93 .state = 0,
94 .events = 0,
95 .func = nullptr,
96 .arg = nullptr,
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +020097};
98
99static fdevent **fd_table = 0;
100static int fd_table_max = 0;
101
Dan Albert08c1d2e2014-09-25 15:10:34 -0700102#ifdef CRAPTASTIC
103//HAVE_EPOLL
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200104
105#include <sys/epoll.h>
106
107static int epoll_fd = -1;
108
109static void fdevent_init()
110{
Dan Albert08c1d2e2014-09-25 15:10:34 -0700111 /* XXX: what's a good size for the passed in hint? */
112 epoll_fd = epoll_create(256);
113
114 if(epoll_fd < 0) {
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200115 perror("epoll_create() failed");
116 exit(1);
117 }
Dan Albert08c1d2e2014-09-25 15:10:34 -0700118
119 /* mark for close-on-exec */
120 fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200121}
122
123static void fdevent_connect(fdevent *fde)
124{
Dan Albert08c1d2e2014-09-25 15:10:34 -0700125 struct epoll_event ev;
126
127 memset(&ev, 0, sizeof(ev));
128 ev.events = 0;
129 ev.data.ptr = fde;
130
131#if 0
132 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
133 perror("epoll_ctl() failed\n");
134 exit(1);
135 }
136#endif
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200137}
138
139static void fdevent_disconnect(fdevent *fde)
140{
141 struct epoll_event ev;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200142
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200143 memset(&ev, 0, sizeof(ev));
144 ev.events = 0;
145 ev.data.ptr = fde;
146
147 /* technically we only need to delete if we
148 ** were actively monitoring events, but let's
149 ** be aggressive and do it anyway, just in case
150 ** something's out of sync
151 */
152 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
153}
154
155static void fdevent_update(fdevent *fde, unsigned events)
156{
157 struct epoll_event ev;
158 int active;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200159
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200160 active = (fde->state & FDE_EVENTMASK) != 0;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200161
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200162 memset(&ev, 0, sizeof(ev));
163 ev.events = 0;
164 ev.data.ptr = fde;
165
166 if(events & FDE_READ) ev.events |= EPOLLIN;
167 if(events & FDE_WRITE) ev.events |= EPOLLOUT;
168 if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
169
170 fde->state = (fde->state & FDE_STATEMASK) | events;
171
172 if(active) {
173 /* we're already active. if we're changing to *no*
174 ** events being monitored, we need to delete, otherwise
175 ** we need to just modify
176 */
177 if(ev.events) {
178 if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
179 perror("epoll_ctl() failed\n");
180 exit(1);
181 }
182 } else {
183 if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
184 perror("epoll_ctl() failed\n");
185 exit(1);
186 }
187 }
188 } else {
189 /* we're not active. if we're watching events, we need
190 ** to add, otherwise we can just do nothing
191 */
192 if(ev.events) {
193 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
194 perror("epoll_ctl() failed\n");
195 exit(1);
196 }
197 }
198 }
199}
200
201static void fdevent_process()
202{
203 struct epoll_event events[256];
204 fdevent *fde;
205 int i, n;
206
207 n = epoll_wait(epoll_fd, events, 256, -1);
208
209 if(n < 0) {
210 if(errno == EINTR) return;
211 perror("epoll_wait");
212 exit(1);
213 }
214
215 for(i = 0; i < n; i++) {
216 struct epoll_event *ev = events + i;
217 fde = ev->data.ptr;
218
219 if(ev->events & EPOLLIN) {
220 fde->events |= FDE_READ;
221 }
222 if(ev->events & EPOLLOUT) {
223 fde->events |= FDE_WRITE;
224 }
225 if(ev->events & (EPOLLERR | EPOLLHUP)) {
226 fde->events |= FDE_ERROR;
227 }
228 if(fde->events) {
229 if(fde->state & FDE_PENDING) continue;
230 fde->state |= FDE_PENDING;
231 fdevent_plist_enqueue(fde);
232 }
233 }
234}
235
236#else /* USE_SELECT */
237
238#ifdef HAVE_WINSOCK
239#include <winsock2.h>
240#else
241#include <sys/select.h>
242#endif
243
244static fd_set read_fds;
245static fd_set write_fds;
246static fd_set error_fds;
247
248static int select_n = 0;
249
250static void fdevent_init(void)
251{
252 FD_ZERO(&read_fds);
253 FD_ZERO(&write_fds);
254 FD_ZERO(&error_fds);
255}
256
257static void fdevent_connect(fdevent *fde)
258{
259 if(fde->fd >= select_n) {
260 select_n = fde->fd + 1;
261 }
262}
263
264static void fdevent_disconnect(fdevent *fde)
265{
266 int i, n;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200267
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200268 FD_CLR(fde->fd, &read_fds);
269 FD_CLR(fde->fd, &write_fds);
270 FD_CLR(fde->fd, &error_fds);
271
272 for(n = 0, i = 0; i < select_n; i++) {
273 if(fd_table[i] != 0) n = i;
274 }
275 select_n = n + 1;
276}
277
278static void fdevent_update(fdevent *fde, unsigned events)
279{
280 if(events & FDE_READ) {
281 FD_SET(fde->fd, &read_fds);
282 } else {
283 FD_CLR(fde->fd, &read_fds);
284 }
285 if(events & FDE_WRITE) {
286 FD_SET(fde->fd, &write_fds);
287 } else {
288 FD_CLR(fde->fd, &write_fds);
289 }
290 if(events & FDE_ERROR) {
291 FD_SET(fde->fd, &error_fds);
292 } else {
293 FD_CLR(fde->fd, &error_fds);
294 }
295
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700296 fde->state = (fde->state & FDE_STATEMASK) | events;
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200297}
298
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700299/* Looks at fd_table[] for bad FDs and sets bit in fds.
300** Returns the number of bad FDs.
301*/
302static int fdevent_fd_check(fd_set *fds)
303{
304 int i, n = 0;
305 fdevent *fde;
306
307 for(i = 0; i < select_n; i++) {
308 fde = fd_table[i];
309 if(fde == 0) continue;
310 if(fcntl(i, F_GETFL, NULL) < 0) {
311 FD_SET(i, fds);
312 n++;
313 // fde->state |= FDE_DONT_CLOSE;
314
315 }
316 }
317 return n;
318}
319
320#if !DEBUG
Dan Albertbbbbea62014-11-24 23:34:35 -0800321static inline void dump_all_fds(const char* /* extra_msg */) {}
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700322#else
323static void dump_all_fds(const char *extra_msg)
324{
325int i;
326 fdevent *fde;
327 // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
328 char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
329 size_t max_chars = FD_SETSIZE * 6 + 1;
330 int printed_out;
331#define SAFE_SPRINTF(...) \
332 do { \
333 printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
334 if (printed_out <= 0) { \
335 D("... snprintf failed.\n"); \
336 return; \
337 } \
338 if (max_chars < (unsigned int)printed_out) { \
339 D("... snprintf out of space.\n"); \
340 return; \
341 } \
342 pb += printed_out; \
343 max_chars -= printed_out; \
344 } while(0)
345
346 for(i = 0; i < select_n; i++) {
347 fde = fd_table[i];
348 SAFE_SPRINTF("%d", i);
349 if(fde == 0) {
350 SAFE_SPRINTF("? ");
351 continue;
352 }
353 if(fcntl(i, F_GETFL, NULL) < 0) {
354 SAFE_SPRINTF("b");
355 }
356 SAFE_SPRINTF(" ");
357 }
358 D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
359}
360#endif
361
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200362static void fdevent_process()
363{
364 int i, n;
365 fdevent *fde;
366 unsigned events;
367 fd_set rfd, wfd, efd;
368
369 memcpy(&rfd, &read_fds, sizeof(fd_set));
370 memcpy(&wfd, &write_fds, sizeof(fd_set));
371 memcpy(&efd, &error_fds, sizeof(fd_set));
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200372
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700373 dump_all_fds("pre select()");
374
375 n = select(select_n, &rfd, &wfd, &efd, NULL);
376 int saved_errno = errno;
377 D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
378
379 dump_all_fds("post select()");
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200380
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200381 if(n < 0) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700382 switch(saved_errno) {
383 case EINTR: return;
384 case EBADF:
385 // Can't trust the FD sets after an error.
386 FD_ZERO(&wfd);
387 FD_ZERO(&efd);
388 FD_ZERO(&rfd);
389 break;
390 default:
391 D("Unexpected select() error=%d\n", saved_errno);
392 return;
393 }
394 }
395 if(n <= 0) {
396 // We fake a read, as the rest of the code assumes
397 // that errors will be detected at that point.
398 n = fdevent_fd_check(&rfd);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200399 }
400
401 for(i = 0; (i < select_n) && (n > 0); i++) {
402 events = 0;
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700403 if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
404 if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
405 if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200406
407 if(events) {
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200408 fde = fd_table[i];
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700409 if(fde == 0)
410 FATAL("missing fde for fd %d\n", i);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200411
412 fde->events |= events;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200413
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700414 D("got events fde->fd=%d events=%04x, state=%04x\n",
415 fde->fd, fde->events, fde->state);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200416 if(fde->state & FDE_PENDING) continue;
417 fde->state |= FDE_PENDING;
418 fdevent_plist_enqueue(fde);
419 }
420 }
421}
422
423#endif
424
425static void fdevent_register(fdevent *fde)
426{
427 if(fde->fd < 0) {
428 FATAL("bogus negative fd (%d)\n", fde->fd);
429 }
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200430
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200431 if(fde->fd >= fd_table_max) {
432 int oldmax = fd_table_max;
433 if(fde->fd > 32000) {
434 FATAL("bogus huuuuge fd (%d)\n", fde->fd);
435 }
436 if(fd_table_max == 0) {
437 fdevent_init();
438 fd_table_max = 256;
439 }
440 while(fd_table_max <= fde->fd) {
441 fd_table_max *= 2;
442 }
Dan Albertbbbbea62014-11-24 23:34:35 -0800443 fd_table = reinterpret_cast<fdevent**>(
444 realloc(fd_table, sizeof(fdevent*) * fd_table_max));
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200445 if(fd_table == 0) {
446 FATAL("could not expand fd_table to %d entries\n", fd_table_max);
447 }
448 memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
449 }
450
451 fd_table[fde->fd] = fde;
452}
453
454static void fdevent_unregister(fdevent *fde)
455{
456 if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
457 FATAL("fd out of range (%d)\n", fde->fd);
458 }
459
460 if(fd_table[fde->fd] != fde) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700461 FATAL("fd_table out of sync [%d]\n", fde->fd);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200462 }
463
464 fd_table[fde->fd] = 0;
465
466 if(!(fde->state & FDE_DONT_CLOSE)) {
467 dump_fde(fde, "close");
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700468 adb_close(fde->fd);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200469 }
470}
471
472static void fdevent_plist_enqueue(fdevent *node)
473{
474 fdevent *list = &list_pending;
475
476 node->next = list;
477 node->prev = list->prev;
478 node->prev->next = node;
479 list->prev = node;
480}
481
482static void fdevent_plist_remove(fdevent *node)
483{
484 node->prev->next = node->next;
485 node->next->prev = node->prev;
486 node->next = 0;
487 node->prev = 0;
488}
489
490static fdevent *fdevent_plist_dequeue(void)
491{
492 fdevent *list = &list_pending;
493 fdevent *node = list->next;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200494
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200495 if(node == list) return 0;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200496
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200497 list->next = node->next;
498 list->next->prev = list;
499 node->next = 0;
500 node->prev = 0;
501
502 return node;
503}
504
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700505static void fdevent_call_fdfunc(fdevent* fde)
506{
507 unsigned events = fde->events;
508 fde->events = 0;
509 if(!(fde->state & FDE_PENDING)) return;
510 fde->state &= (~FDE_PENDING);
511 dump_fde(fde, "callback");
512 fde->func(fde->fd, events, fde->arg);
513}
514
Dan Albertbbbbea62014-11-24 23:34:35 -0800515static void fdevent_subproc_event_func(int fd, unsigned ev,
516 void* /* userdata */)
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700517{
518
519 D("subproc handling on fd=%d ev=%04x\n", fd, ev);
520
521 // Hook oneself back into the fde's suitable for select() on read.
522 if((fd < 0) || (fd >= fd_table_max)) {
523 FATAL("fd %d out of range for fd_table \n", fd);
524 }
525 fdevent *fde = fd_table[fd];
526 fdevent_add(fde, FDE_READ);
527
528 if(ev & FDE_READ){
529 int subproc_fd;
530
531 if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
532 FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
533 }
534 if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
535 D("subproc_fd %d out of range 0, fd_table_max=%d\n",
536 subproc_fd, fd_table_max);
537 return;
538 }
539 fdevent *subproc_fde = fd_table[subproc_fd];
540 if(!subproc_fde) {
541 D("subproc_fd %d cleared from fd_table\n", subproc_fd);
542 return;
543 }
544 if(subproc_fde->fd != subproc_fd) {
545 // Already reallocated?
546 D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
547 return;
548 }
549
550 subproc_fde->force_eof = 1;
551
552 int rcount = 0;
JP Abgrall6809eaf2011-03-29 12:36:22 -0700553 ioctl(subproc_fd, FIONREAD, &rcount);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700554 D("subproc with fd=%d has rcount=%d err=%d\n",
555 subproc_fd, rcount, errno);
556
557 if(rcount) {
558 // If there is data left, it will show up in the select().
559 // This works because there is no other thread reading that
560 // data when in this fd_func().
561 return;
562 }
563
564 D("subproc_fde.state=%04x\n", subproc_fde->state);
565 subproc_fde->events |= FDE_READ;
566 if(subproc_fde->state & FDE_PENDING) {
567 return;
568 }
569 subproc_fde->state |= FDE_PENDING;
570 fdevent_call_fdfunc(subproc_fde);
571 }
572}
573
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200574fdevent *fdevent_create(int fd, fd_func func, void *arg)
575{
576 fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
577 if(fde == 0) return 0;
578 fdevent_install(fde, fd, func, arg);
579 fde->state |= FDE_CREATED;
580 return fde;
581}
582
583void fdevent_destroy(fdevent *fde)
584{
585 if(fde == 0) return;
586 if(!(fde->state & FDE_CREATED)) {
587 FATAL("fde %p not created by fdevent_create()\n", fde);
588 }
589 fdevent_remove(fde);
590}
591
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700592void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200593{
594 memset(fde, 0, sizeof(fdevent));
595 fde->state = FDE_ACTIVE;
596 fde->fd = fd;
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700597 fde->force_eof = 0;
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200598 fde->func = func;
599 fde->arg = arg;
600
601#ifndef HAVE_WINSOCK
602 fcntl(fd, F_SETFL, O_NONBLOCK);
603#endif
604 fdevent_register(fde);
605 dump_fde(fde, "connect");
606 fdevent_connect(fde);
607 fde->state |= FDE_ACTIVE;
608}
609
610void fdevent_remove(fdevent *fde)
611{
612 if(fde->state & FDE_PENDING) {
613 fdevent_plist_remove(fde);
614 }
615
616 if(fde->state & FDE_ACTIVE) {
617 fdevent_disconnect(fde);
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700618 dump_fde(fde, "disconnect");
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200619 fdevent_unregister(fde);
620 }
621
622 fde->state = 0;
623 fde->events = 0;
624}
625
626
627void fdevent_set(fdevent *fde, unsigned events)
628{
629 events &= FDE_EVENTMASK;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200630
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200631 if((fde->state & FDE_EVENTMASK) == events) return;
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200632
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200633 if(fde->state & FDE_ACTIVE) {
634 fdevent_update(fde, events);
635 dump_fde(fde, "update");
636 }
637
638 fde->state = (fde->state & FDE_STATEMASK) | events;
639
640 if(fde->state & FDE_PENDING) {
641 /* if we're pending, make sure
642 ** we don't signal an event that
643 ** is no longer wanted.
644 */
645 fde->events &= (~events);
646 if(fde->events == 0) {
647 fdevent_plist_remove(fde);
648 fde->state &= (~FDE_PENDING);
649 }
650 }
651}
652
653void fdevent_add(fdevent *fde, unsigned events)
654{
655 fdevent_set(
656 fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
657}
658
659void fdevent_del(fdevent *fde, unsigned events)
660{
661 fdevent_set(
662 fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
663}
664
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700665void fdevent_subproc_setup()
666{
667 int s[2];
668
669 if(adb_socketpair(s)) {
670 FATAL("cannot create shell-exit socket-pair\n");
671 }
leozwang1be54622014-08-15 09:51:27 -0700672 D("socketpair: (%d,%d)", s[0], s[1]);
673
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700674 SHELL_EXIT_NOTIFY_FD = s[0];
675 fdevent *fde;
676 fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
677 if(!fde)
678 FATAL("cannot create fdevent for shell-exit handler\n");
679 fdevent_add(fde, FDE_READ);
680}
681
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200682void fdevent_loop()
683{
684 fdevent *fde;
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700685 fdevent_subproc_setup();
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200686
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200687 for(;;) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700688 D("--- ---- waiting for events\n");
689
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200690 fdevent_process();
David 'Digit' Turner1f1efb52009-05-18 17:36:28 +0200691
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200692 while((fde = fdevent_plist_dequeue())) {
JP Abgrall2e5dd6e2011-03-16 15:57:42 -0700693 fdevent_call_fdfunc(fde);
David 'Digit' Turnerb1c2c952009-05-18 17:07:46 +0200694 }
695 }
696}