blob: 5c374a71bff8b64338547fdfd2d36f1c6c343cff [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**
JP Abgrall0e7c4272011-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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08008**
JP Abgrall0e7c4272011-02-23 18:44:39 -08009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080010**
JP Abgrall0e7c4272011-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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080015** limitations under the License.
16*/
17
JP Abgrall408fa572011-03-16 15:57:42 -070018#include <sys/ioctl.h>
19
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080020#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
David 'Digit' Turner414ff7d2009-05-18 17:07:46 +020031#include "fdevent.h"
JP Abgrall408fa572011-03-16 15:57:42 -070032#include "transport.h"
33#include "sysdeps.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035
JP Abgrall408fa572011-03-16 15:57:42 -070036/* !!! Do not enable DEBUG for the adb that will run as the server:
37** both stdout and stderr are used to communicate between the client
38** and server. Any extra output will cause failures.
39*/
40#define DEBUG 0 /* non-0 will break adb server */
41
42// This socket is used when a subproc shell service exists.
43// It wakes up the fdevent_loop() and cause the correct handling
44// of the shell's pseudo-tty master. I.e. force close it.
45int SHELL_EXIT_NOTIFY_FD = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080046
47static void fatal(const char *fn, const char *fmt, ...)
48{
49 va_list ap;
50 va_start(ap, fmt);
51 fprintf(stderr, "%s:", fn);
52 vfprintf(stderr, fmt, ap);
53 va_end(ap);
54 abort();
55}
56
57#define FATAL(x...) fatal(__FUNCTION__, x)
58
59#if DEBUG
JP Abgrall408fa572011-03-16 15:57:42 -070060#define D(...) \
61 do { \
62 adb_mutex_lock(&D_lock); \
63 int save_errno = errno; \
64 fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
65 errno = save_errno; \
66 fprintf(stderr, __VA_ARGS__); \
67 adb_mutex_unlock(&D_lock); \
68 errno = save_errno; \
69 } while(0)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080070static void dump_fde(fdevent *fde, const char *info)
71{
JP Abgrall408fa572011-03-16 15:57:42 -070072 adb_mutex_lock(&D_lock);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080073 fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
74 fde->state & FDE_READ ? 'R' : ' ',
75 fde->state & FDE_WRITE ? 'W' : ' ',
76 fde->state & FDE_ERROR ? 'E' : ' ',
77 info);
JP Abgrall408fa572011-03-16 15:57:42 -070078 adb_mutex_unlock(&D_lock);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079}
80#else
JP Abgrall408fa572011-03-16 15:57:42 -070081#define D(...) ((void)0)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080082#define dump_fde(fde, info) do { } while(0)
83#endif
84
85#define FDE_EVENTMASK 0x00ff
86#define FDE_STATEMASK 0xff00
87
88#define FDE_ACTIVE 0x0100
89#define FDE_PENDING 0x0200
90#define FDE_CREATED 0x0400
91
92static void fdevent_plist_enqueue(fdevent *node);
93static void fdevent_plist_remove(fdevent *node);
94static fdevent *fdevent_plist_dequeue(void);
JP Abgrall408fa572011-03-16 15:57:42 -070095static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096
97static fdevent list_pending = {
98 .next = &list_pending,
99 .prev = &list_pending,
100};
101
102static fdevent **fd_table = 0;
103static int fd_table_max = 0;
104
Dan Albert45741ae2014-09-25 15:10:34 -0700105#ifdef CRAPTASTIC
106//HAVE_EPOLL
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107
108#include <sys/epoll.h>
109
110static int epoll_fd = -1;
111
112static void fdevent_init()
113{
Dan Albert45741ae2014-09-25 15:10:34 -0700114 /* XXX: what's a good size for the passed in hint? */
115 epoll_fd = epoll_create(256);
116
117 if(epoll_fd < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800118 perror("epoll_create() failed");
119 exit(1);
120 }
Dan Albert45741ae2014-09-25 15:10:34 -0700121
122 /* mark for close-on-exec */
123 fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800124}
125
126static void fdevent_connect(fdevent *fde)
127{
Dan Albert45741ae2014-09-25 15:10:34 -0700128 struct epoll_event ev;
129
130 memset(&ev, 0, sizeof(ev));
131 ev.events = 0;
132 ev.data.ptr = fde;
133
134#if 0
135 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
136 perror("epoll_ctl() failed\n");
137 exit(1);
138 }
139#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800140}
141
142static void fdevent_disconnect(fdevent *fde)
143{
144 struct epoll_event ev;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200145
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800146 memset(&ev, 0, sizeof(ev));
147 ev.events = 0;
148 ev.data.ptr = fde;
149
150 /* technically we only need to delete if we
151 ** were actively monitoring events, but let's
152 ** be aggressive and do it anyway, just in case
153 ** something's out of sync
154 */
155 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
156}
157
158static void fdevent_update(fdevent *fde, unsigned events)
159{
160 struct epoll_event ev;
161 int active;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200162
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163 active = (fde->state & FDE_EVENTMASK) != 0;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200164
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165 memset(&ev, 0, sizeof(ev));
166 ev.events = 0;
167 ev.data.ptr = fde;
168
169 if(events & FDE_READ) ev.events |= EPOLLIN;
170 if(events & FDE_WRITE) ev.events |= EPOLLOUT;
171 if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
172
173 fde->state = (fde->state & FDE_STATEMASK) | events;
174
175 if(active) {
176 /* we're already active. if we're changing to *no*
177 ** events being monitored, we need to delete, otherwise
178 ** we need to just modify
179 */
180 if(ev.events) {
181 if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
182 perror("epoll_ctl() failed\n");
183 exit(1);
184 }
185 } else {
186 if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
187 perror("epoll_ctl() failed\n");
188 exit(1);
189 }
190 }
191 } else {
192 /* we're not active. if we're watching events, we need
193 ** to add, otherwise we can just do nothing
194 */
195 if(ev.events) {
196 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
197 perror("epoll_ctl() failed\n");
198 exit(1);
199 }
200 }
201 }
202}
203
204static void fdevent_process()
205{
206 struct epoll_event events[256];
207 fdevent *fde;
208 int i, n;
209
210 n = epoll_wait(epoll_fd, events, 256, -1);
211
212 if(n < 0) {
213 if(errno == EINTR) return;
214 perror("epoll_wait");
215 exit(1);
216 }
217
218 for(i = 0; i < n; i++) {
219 struct epoll_event *ev = events + i;
220 fde = ev->data.ptr;
221
222 if(ev->events & EPOLLIN) {
223 fde->events |= FDE_READ;
224 }
225 if(ev->events & EPOLLOUT) {
226 fde->events |= FDE_WRITE;
227 }
228 if(ev->events & (EPOLLERR | EPOLLHUP)) {
229 fde->events |= FDE_ERROR;
230 }
231 if(fde->events) {
232 if(fde->state & FDE_PENDING) continue;
233 fde->state |= FDE_PENDING;
234 fdevent_plist_enqueue(fde);
235 }
236 }
237}
238
239#else /* USE_SELECT */
240
241#ifdef HAVE_WINSOCK
242#include <winsock2.h>
243#else
244#include <sys/select.h>
245#endif
246
247static fd_set read_fds;
248static fd_set write_fds;
249static fd_set error_fds;
250
251static int select_n = 0;
252
253static void fdevent_init(void)
254{
255 FD_ZERO(&read_fds);
256 FD_ZERO(&write_fds);
257 FD_ZERO(&error_fds);
258}
259
260static void fdevent_connect(fdevent *fde)
261{
262 if(fde->fd >= select_n) {
263 select_n = fde->fd + 1;
264 }
265}
266
267static void fdevent_disconnect(fdevent *fde)
268{
269 int i, n;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200270
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800271 FD_CLR(fde->fd, &read_fds);
272 FD_CLR(fde->fd, &write_fds);
273 FD_CLR(fde->fd, &error_fds);
274
275 for(n = 0, i = 0; i < select_n; i++) {
276 if(fd_table[i] != 0) n = i;
277 }
278 select_n = n + 1;
279}
280
281static void fdevent_update(fdevent *fde, unsigned events)
282{
283 if(events & FDE_READ) {
284 FD_SET(fde->fd, &read_fds);
285 } else {
286 FD_CLR(fde->fd, &read_fds);
287 }
288 if(events & FDE_WRITE) {
289 FD_SET(fde->fd, &write_fds);
290 } else {
291 FD_CLR(fde->fd, &write_fds);
292 }
293 if(events & FDE_ERROR) {
294 FD_SET(fde->fd, &error_fds);
295 } else {
296 FD_CLR(fde->fd, &error_fds);
297 }
298
JP Abgrall408fa572011-03-16 15:57:42 -0700299 fde->state = (fde->state & FDE_STATEMASK) | events;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800300}
301
JP Abgrall408fa572011-03-16 15:57:42 -0700302/* Looks at fd_table[] for bad FDs and sets bit in fds.
303** Returns the number of bad FDs.
304*/
305static int fdevent_fd_check(fd_set *fds)
306{
307 int i, n = 0;
308 fdevent *fde;
309
310 for(i = 0; i < select_n; i++) {
311 fde = fd_table[i];
312 if(fde == 0) continue;
313 if(fcntl(i, F_GETFL, NULL) < 0) {
314 FD_SET(i, fds);
315 n++;
316 // fde->state |= FDE_DONT_CLOSE;
317
318 }
319 }
320 return n;
321}
322
323#if !DEBUG
324static inline void dump_all_fds(const char *extra_msg) {}
325#else
326static void dump_all_fds(const char *extra_msg)
327{
328int i;
329 fdevent *fde;
330 // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
331 char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
332 size_t max_chars = FD_SETSIZE * 6 + 1;
333 int printed_out;
334#define SAFE_SPRINTF(...) \
335 do { \
336 printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
337 if (printed_out <= 0) { \
338 D("... snprintf failed.\n"); \
339 return; \
340 } \
341 if (max_chars < (unsigned int)printed_out) { \
342 D("... snprintf out of space.\n"); \
343 return; \
344 } \
345 pb += printed_out; \
346 max_chars -= printed_out; \
347 } while(0)
348
349 for(i = 0; i < select_n; i++) {
350 fde = fd_table[i];
351 SAFE_SPRINTF("%d", i);
352 if(fde == 0) {
353 SAFE_SPRINTF("? ");
354 continue;
355 }
356 if(fcntl(i, F_GETFL, NULL) < 0) {
357 SAFE_SPRINTF("b");
358 }
359 SAFE_SPRINTF(" ");
360 }
361 D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
362}
363#endif
364
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800365static void fdevent_process()
366{
367 int i, n;
368 fdevent *fde;
369 unsigned events;
370 fd_set rfd, wfd, efd;
371
372 memcpy(&rfd, &read_fds, sizeof(fd_set));
373 memcpy(&wfd, &write_fds, sizeof(fd_set));
374 memcpy(&efd, &error_fds, sizeof(fd_set));
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200375
JP Abgrall408fa572011-03-16 15:57:42 -0700376 dump_all_fds("pre select()");
377
378 n = select(select_n, &rfd, &wfd, &efd, NULL);
379 int saved_errno = errno;
380 D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
381
382 dump_all_fds("post select()");
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200383
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800384 if(n < 0) {
JP Abgrall408fa572011-03-16 15:57:42 -0700385 switch(saved_errno) {
386 case EINTR: return;
387 case EBADF:
388 // Can't trust the FD sets after an error.
389 FD_ZERO(&wfd);
390 FD_ZERO(&efd);
391 FD_ZERO(&rfd);
392 break;
393 default:
394 D("Unexpected select() error=%d\n", saved_errno);
395 return;
396 }
397 }
398 if(n <= 0) {
399 // We fake a read, as the rest of the code assumes
400 // that errors will be detected at that point.
401 n = fdevent_fd_check(&rfd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800402 }
403
404 for(i = 0; (i < select_n) && (n > 0); i++) {
405 events = 0;
JP Abgrall408fa572011-03-16 15:57:42 -0700406 if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
407 if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
408 if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800409
410 if(events) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800411 fde = fd_table[i];
JP Abgrall408fa572011-03-16 15:57:42 -0700412 if(fde == 0)
413 FATAL("missing fde for fd %d\n", i);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800414
415 fde->events |= events;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200416
JP Abgrall408fa572011-03-16 15:57:42 -0700417 D("got events fde->fd=%d events=%04x, state=%04x\n",
418 fde->fd, fde->events, fde->state);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800419 if(fde->state & FDE_PENDING) continue;
420 fde->state |= FDE_PENDING;
421 fdevent_plist_enqueue(fde);
422 }
423 }
424}
425
426#endif
427
428static void fdevent_register(fdevent *fde)
429{
430 if(fde->fd < 0) {
431 FATAL("bogus negative fd (%d)\n", fde->fd);
432 }
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200433
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800434 if(fde->fd >= fd_table_max) {
435 int oldmax = fd_table_max;
436 if(fde->fd > 32000) {
437 FATAL("bogus huuuuge fd (%d)\n", fde->fd);
438 }
439 if(fd_table_max == 0) {
440 fdevent_init();
441 fd_table_max = 256;
442 }
443 while(fd_table_max <= fde->fd) {
444 fd_table_max *= 2;
445 }
446 fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
447 if(fd_table == 0) {
448 FATAL("could not expand fd_table to %d entries\n", fd_table_max);
449 }
450 memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
451 }
452
453 fd_table[fde->fd] = fde;
454}
455
456static void fdevent_unregister(fdevent *fde)
457{
458 if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
459 FATAL("fd out of range (%d)\n", fde->fd);
460 }
461
462 if(fd_table[fde->fd] != fde) {
JP Abgrall408fa572011-03-16 15:57:42 -0700463 FATAL("fd_table out of sync [%d]\n", fde->fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800464 }
465
466 fd_table[fde->fd] = 0;
467
468 if(!(fde->state & FDE_DONT_CLOSE)) {
469 dump_fde(fde, "close");
JP Abgrall408fa572011-03-16 15:57:42 -0700470 adb_close(fde->fd);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800471 }
472}
473
474static void fdevent_plist_enqueue(fdevent *node)
475{
476 fdevent *list = &list_pending;
477
478 node->next = list;
479 node->prev = list->prev;
480 node->prev->next = node;
481 list->prev = node;
482}
483
484static void fdevent_plist_remove(fdevent *node)
485{
486 node->prev->next = node->next;
487 node->next->prev = node->prev;
488 node->next = 0;
489 node->prev = 0;
490}
491
492static fdevent *fdevent_plist_dequeue(void)
493{
494 fdevent *list = &list_pending;
495 fdevent *node = list->next;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200496
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800497 if(node == list) return 0;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200498
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800499 list->next = node->next;
500 list->next->prev = list;
501 node->next = 0;
502 node->prev = 0;
503
504 return node;
505}
506
JP Abgrall408fa572011-03-16 15:57:42 -0700507static void fdevent_call_fdfunc(fdevent* fde)
508{
509 unsigned events = fde->events;
510 fde->events = 0;
511 if(!(fde->state & FDE_PENDING)) return;
512 fde->state &= (~FDE_PENDING);
513 dump_fde(fde, "callback");
514 fde->func(fde->fd, events, fde->arg);
515}
516
517static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
518{
519
520 D("subproc handling on fd=%d ev=%04x\n", fd, ev);
521
522 // Hook oneself back into the fde's suitable for select() on read.
523 if((fd < 0) || (fd >= fd_table_max)) {
524 FATAL("fd %d out of range for fd_table \n", fd);
525 }
526 fdevent *fde = fd_table[fd];
527 fdevent_add(fde, FDE_READ);
528
529 if(ev & FDE_READ){
530 int subproc_fd;
531
532 if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
533 FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
534 }
535 if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
536 D("subproc_fd %d out of range 0, fd_table_max=%d\n",
537 subproc_fd, fd_table_max);
538 return;
539 }
540 fdevent *subproc_fde = fd_table[subproc_fd];
541 if(!subproc_fde) {
542 D("subproc_fd %d cleared from fd_table\n", subproc_fd);
543 return;
544 }
545 if(subproc_fde->fd != subproc_fd) {
546 // Already reallocated?
547 D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
548 return;
549 }
550
551 subproc_fde->force_eof = 1;
552
553 int rcount = 0;
JP Abgrallb40367e2011-03-29 12:36:22 -0700554 ioctl(subproc_fd, FIONREAD, &rcount);
JP Abgrall408fa572011-03-16 15:57:42 -0700555 D("subproc with fd=%d has rcount=%d err=%d\n",
556 subproc_fd, rcount, errno);
557
558 if(rcount) {
559 // If there is data left, it will show up in the select().
560 // This works because there is no other thread reading that
561 // data when in this fd_func().
562 return;
563 }
564
565 D("subproc_fde.state=%04x\n", subproc_fde->state);
566 subproc_fde->events |= FDE_READ;
567 if(subproc_fde->state & FDE_PENDING) {
568 return;
569 }
570 subproc_fde->state |= FDE_PENDING;
571 fdevent_call_fdfunc(subproc_fde);
572 }
573}
574
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800575fdevent *fdevent_create(int fd, fd_func func, void *arg)
576{
577 fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
578 if(fde == 0) return 0;
579 fdevent_install(fde, fd, func, arg);
580 fde->state |= FDE_CREATED;
581 return fde;
582}
583
584void fdevent_destroy(fdevent *fde)
585{
586 if(fde == 0) return;
587 if(!(fde->state & FDE_CREATED)) {
588 FATAL("fde %p not created by fdevent_create()\n", fde);
589 }
590 fdevent_remove(fde);
591}
592
JP Abgrall408fa572011-03-16 15:57:42 -0700593void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800594{
595 memset(fde, 0, sizeof(fdevent));
596 fde->state = FDE_ACTIVE;
597 fde->fd = fd;
JP Abgrall408fa572011-03-16 15:57:42 -0700598 fde->force_eof = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800599 fde->func = func;
600 fde->arg = arg;
601
602#ifndef HAVE_WINSOCK
603 fcntl(fd, F_SETFL, O_NONBLOCK);
604#endif
605 fdevent_register(fde);
606 dump_fde(fde, "connect");
607 fdevent_connect(fde);
608 fde->state |= FDE_ACTIVE;
609}
610
611void fdevent_remove(fdevent *fde)
612{
613 if(fde->state & FDE_PENDING) {
614 fdevent_plist_remove(fde);
615 }
616
617 if(fde->state & FDE_ACTIVE) {
618 fdevent_disconnect(fde);
JP Abgrall408fa572011-03-16 15:57:42 -0700619 dump_fde(fde, "disconnect");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800620 fdevent_unregister(fde);
621 }
622
623 fde->state = 0;
624 fde->events = 0;
625}
626
627
628void fdevent_set(fdevent *fde, unsigned events)
629{
630 events &= FDE_EVENTMASK;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200631
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800632 if((fde->state & FDE_EVENTMASK) == events) return;
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200633
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800634 if(fde->state & FDE_ACTIVE) {
635 fdevent_update(fde, events);
636 dump_fde(fde, "update");
637 }
638
639 fde->state = (fde->state & FDE_STATEMASK) | events;
640
641 if(fde->state & FDE_PENDING) {
642 /* if we're pending, make sure
643 ** we don't signal an event that
644 ** is no longer wanted.
645 */
646 fde->events &= (~events);
647 if(fde->events == 0) {
648 fdevent_plist_remove(fde);
649 fde->state &= (~FDE_PENDING);
650 }
651 }
652}
653
654void fdevent_add(fdevent *fde, unsigned events)
655{
656 fdevent_set(
657 fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
658}
659
660void fdevent_del(fdevent *fde, unsigned events)
661{
662 fdevent_set(
663 fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
664}
665
JP Abgrall408fa572011-03-16 15:57:42 -0700666void fdevent_subproc_setup()
667{
668 int s[2];
669
670 if(adb_socketpair(s)) {
671 FATAL("cannot create shell-exit socket-pair\n");
672 }
673 SHELL_EXIT_NOTIFY_FD = s[0];
674 fdevent *fde;
675 fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
676 if(!fde)
677 FATAL("cannot create fdevent for shell-exit handler\n");
678 fdevent_add(fde, FDE_READ);
679}
680
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800681void fdevent_loop()
682{
683 fdevent *fde;
JP Abgrall408fa572011-03-16 15:57:42 -0700684 fdevent_subproc_setup();
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200685
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800686 for(;;) {
JP Abgrall408fa572011-03-16 15:57:42 -0700687 D("--- ---- waiting for events\n");
688
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800689 fdevent_process();
David 'Digit' Turnerf6330a22009-05-18 17:36:28 +0200690
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800691 while((fde = fdevent_plist_dequeue())) {
JP Abgrall408fa572011-03-16 15:57:42 -0700692 fdevent_call_fdfunc(fde);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800693 }
694 }
695}