| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 1 | /* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c | 
 | 2 | ** | 
 | 3 | ** Copyright 2006, Brian Swetland <swetland@frotz.net> | 
 | 4 | ** | 
| JP Abgrall | 0e7c427 | 2011-02-23 18:44:39 -0800 | [diff] [blame] | 5 | ** 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 Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 8 | ** | 
| JP Abgrall | 0e7c427 | 2011-02-23 18:44:39 -0800 | [diff] [blame] | 9 | **     http://www.apache.org/licenses/LICENSE-2.0  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 10 | ** | 
| JP Abgrall | 0e7c427 | 2011-02-23 18:44:39 -0800 | [diff] [blame] | 11 | ** 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 Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 15 | ** limitations under the License. | 
 | 16 | */ | 
 | 17 |  | 
| Dan Albert | 3313426 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 18 | #define TRACE_TAG TRACE_FDEVENT | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 19 |  | 
| Dan Albert | 3313426 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 20 | #include "sysdeps.h" | 
 | 21 | #include "fdevent.h" | 
 | 22 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 23 | #include <errno.h> | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 24 | #include <fcntl.h> | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 25 | #include <stdarg.h> | 
 | 26 | #include <stddef.h> | 
| Dan Albert | 3313426 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 27 | #include <stdio.h> | 
 | 28 | #include <stdlib.h> | 
 | 29 | #include <string.h> | 
 | 30 | #include <sys/ioctl.h> | 
 | 31 | #include <unistd.h> | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 32 |  | 
| Dan Albert | cc731cc | 2015-02-24 21:26:58 -0800 | [diff] [blame] | 33 | #include "adb_io.h" | 
| leozwang | d3fc15f | 2014-07-29 12:50:02 -0700 | [diff] [blame] | 34 | #include "adb_trace.h" | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 35 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 36 | /* !!! 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. | 
 | 45 | int SHELL_EXIT_NOTIFY_FD = -1; | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 46 |  | 
 | 47 | static 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 | 
 | 60 | static void dump_fde(fdevent *fde, const char *info) | 
 | 61 | { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 62 |     adb_mutex_lock(&D_lock); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 63 |     fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, | 
 | 64 |             fde->state & FDE_READ ? 'R' : ' ', | 
 | 65 |             fde->state & FDE_WRITE ? 'W' : ' ', | 
 | 66 |             fde->state & FDE_ERROR ? 'E' : ' ', | 
 | 67 |             info); | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 68 |     adb_mutex_unlock(&D_lock); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 69 | } | 
 | 70 | #else | 
 | 71 | #define dump_fde(fde, info) do { } while(0) | 
 | 72 | #endif | 
 | 73 |  | 
 | 74 | #define FDE_EVENTMASK  0x00ff | 
 | 75 | #define FDE_STATEMASK  0xff00 | 
 | 76 |  | 
 | 77 | #define FDE_ACTIVE     0x0100 | 
 | 78 | #define FDE_PENDING    0x0200 | 
 | 79 | #define FDE_CREATED    0x0400 | 
 | 80 |  | 
 | 81 | static void fdevent_plist_enqueue(fdevent *node); | 
 | 82 | static void fdevent_plist_remove(fdevent *node); | 
 | 83 | static fdevent *fdevent_plist_dequeue(void); | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 84 | static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 85 |  | 
 | 86 | static fdevent list_pending = { | 
 | 87 |     .next = &list_pending, | 
 | 88 |     .prev = &list_pending, | 
| Dan Albert | 630b9af | 2014-11-24 23:34:35 -0800 | [diff] [blame] | 89 |     .fd = -1, | 
 | 90 |     .force_eof = 0, | 
 | 91 |     .state = 0, | 
 | 92 |     .events = 0, | 
 | 93 |     .func = nullptr, | 
 | 94 |     .arg = nullptr, | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 95 | }; | 
 | 96 |  | 
 | 97 | static fdevent **fd_table = 0; | 
 | 98 | static int fd_table_max = 0; | 
 | 99 |  | 
| Dan Albert | 45741ae | 2014-09-25 15:10:34 -0700 | [diff] [blame] | 100 | #ifdef CRAPTASTIC | 
 | 101 | //HAVE_EPOLL | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 102 |  | 
 | 103 | #include <sys/epoll.h> | 
 | 104 |  | 
 | 105 | static int epoll_fd = -1; | 
 | 106 |  | 
 | 107 | static void fdevent_init() | 
 | 108 | { | 
| Dan Albert | 45741ae | 2014-09-25 15:10:34 -0700 | [diff] [blame] | 109 |         /* XXX: what's a good size for the passed in hint? */ | 
 | 110 |     epoll_fd = epoll_create(256); | 
 | 111 |  | 
 | 112 |     if(epoll_fd < 0) { | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 113 |         perror("epoll_create() failed"); | 
 | 114 |         exit(1); | 
 | 115 |     } | 
| Dan Albert | 45741ae | 2014-09-25 15:10:34 -0700 | [diff] [blame] | 116 |  | 
 | 117 |         /* mark for close-on-exec */ | 
 | 118 |     fcntl(epoll_fd, F_SETFD, FD_CLOEXEC); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 119 | } | 
 | 120 |  | 
 | 121 | static void fdevent_connect(fdevent *fde) | 
 | 122 | { | 
| Dan Albert | 45741ae | 2014-09-25 15:10:34 -0700 | [diff] [blame] | 123 |     struct epoll_event ev; | 
 | 124 |  | 
 | 125 |     memset(&ev, 0, sizeof(ev)); | 
 | 126 |     ev.events = 0; | 
 | 127 |     ev.data.ptr = fde; | 
 | 128 |  | 
 | 129 | #if 0 | 
 | 130 |     if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { | 
 | 131 |         perror("epoll_ctl() failed\n"); | 
 | 132 |         exit(1); | 
 | 133 |     } | 
 | 134 | #endif | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 135 | } | 
 | 136 |  | 
 | 137 | static void fdevent_disconnect(fdevent *fde) | 
 | 138 | { | 
 | 139 |     struct epoll_event ev; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 140 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 141 |     memset(&ev, 0, sizeof(ev)); | 
 | 142 |     ev.events = 0; | 
 | 143 |     ev.data.ptr = fde; | 
 | 144 |  | 
 | 145 |         /* technically we only need to delete if we | 
 | 146 |         ** were actively monitoring events, but let's | 
 | 147 |         ** be aggressive and do it anyway, just in case | 
 | 148 |         ** something's out of sync | 
 | 149 |         */ | 
 | 150 |     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev); | 
 | 151 | } | 
 | 152 |  | 
 | 153 | static void fdevent_update(fdevent *fde, unsigned events) | 
 | 154 | { | 
 | 155 |     struct epoll_event ev; | 
 | 156 |     int active; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 157 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 158 |     active = (fde->state & FDE_EVENTMASK) != 0; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 159 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 160 |     memset(&ev, 0, sizeof(ev)); | 
 | 161 |     ev.events = 0; | 
 | 162 |     ev.data.ptr = fde; | 
 | 163 |  | 
 | 164 |     if(events & FDE_READ) ev.events |= EPOLLIN; | 
 | 165 |     if(events & FDE_WRITE) ev.events |= EPOLLOUT; | 
 | 166 |     if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP); | 
 | 167 |  | 
 | 168 |     fde->state = (fde->state & FDE_STATEMASK) | events; | 
 | 169 |  | 
 | 170 |     if(active) { | 
 | 171 |             /* we're already active. if we're changing to *no* | 
 | 172 |             ** events being monitored, we need to delete, otherwise | 
 | 173 |             ** we need to just modify | 
 | 174 |             */ | 
 | 175 |         if(ev.events) { | 
 | 176 |             if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) { | 
 | 177 |                 perror("epoll_ctl() failed\n"); | 
 | 178 |                 exit(1); | 
 | 179 |             } | 
 | 180 |         } else { | 
 | 181 |             if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) { | 
 | 182 |                 perror("epoll_ctl() failed\n"); | 
 | 183 |                 exit(1); | 
 | 184 |             } | 
 | 185 |         } | 
 | 186 |     } else { | 
 | 187 |             /* we're not active.  if we're watching events, we need | 
 | 188 |             ** to add, otherwise we can just do nothing | 
 | 189 |             */ | 
 | 190 |         if(ev.events) { | 
 | 191 |             if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) { | 
 | 192 |                 perror("epoll_ctl() failed\n"); | 
 | 193 |                 exit(1); | 
 | 194 |             } | 
 | 195 |         } | 
 | 196 |     } | 
 | 197 | } | 
 | 198 |  | 
 | 199 | static void fdevent_process() | 
 | 200 | { | 
 | 201 |     struct epoll_event events[256]; | 
 | 202 |     fdevent *fde; | 
 | 203 |     int i, n; | 
 | 204 |  | 
 | 205 |     n = epoll_wait(epoll_fd, events, 256, -1); | 
 | 206 |  | 
 | 207 |     if(n < 0) { | 
 | 208 |         if(errno == EINTR) return; | 
 | 209 |         perror("epoll_wait"); | 
 | 210 |         exit(1); | 
 | 211 |     } | 
 | 212 |  | 
 | 213 |     for(i = 0; i < n; i++) { | 
 | 214 |         struct epoll_event *ev = events + i; | 
 | 215 |         fde = ev->data.ptr; | 
 | 216 |  | 
 | 217 |         if(ev->events & EPOLLIN) { | 
 | 218 |             fde->events |= FDE_READ; | 
 | 219 |         } | 
 | 220 |         if(ev->events & EPOLLOUT) { | 
 | 221 |             fde->events |= FDE_WRITE; | 
 | 222 |         } | 
 | 223 |         if(ev->events & (EPOLLERR | EPOLLHUP)) { | 
 | 224 |             fde->events |= FDE_ERROR; | 
 | 225 |         } | 
 | 226 |         if(fde->events) { | 
 | 227 |             if(fde->state & FDE_PENDING) continue; | 
 | 228 |             fde->state |= FDE_PENDING; | 
 | 229 |             fdevent_plist_enqueue(fde); | 
 | 230 |         } | 
 | 231 |     } | 
 | 232 | } | 
 | 233 |  | 
 | 234 | #else /* USE_SELECT */ | 
 | 235 |  | 
 | 236 | #ifdef HAVE_WINSOCK | 
 | 237 | #include <winsock2.h> | 
 | 238 | #else | 
 | 239 | #include <sys/select.h> | 
 | 240 | #endif | 
 | 241 |  | 
 | 242 | static fd_set read_fds; | 
 | 243 | static fd_set write_fds; | 
 | 244 | static fd_set error_fds; | 
 | 245 |  | 
 | 246 | static int select_n = 0; | 
 | 247 |  | 
 | 248 | static void fdevent_init(void) | 
 | 249 | { | 
 | 250 |     FD_ZERO(&read_fds); | 
 | 251 |     FD_ZERO(&write_fds); | 
 | 252 |     FD_ZERO(&error_fds); | 
 | 253 | } | 
 | 254 |  | 
 | 255 | static void fdevent_connect(fdevent *fde) | 
 | 256 | { | 
 | 257 |     if(fde->fd >= select_n) { | 
 | 258 |         select_n = fde->fd + 1; | 
 | 259 |     } | 
 | 260 | } | 
 | 261 |  | 
 | 262 | static void fdevent_disconnect(fdevent *fde) | 
 | 263 | { | 
 | 264 |     int i, n; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 265 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 266 |     FD_CLR(fde->fd, &read_fds); | 
 | 267 |     FD_CLR(fde->fd, &write_fds); | 
 | 268 |     FD_CLR(fde->fd, &error_fds); | 
 | 269 |  | 
 | 270 |     for(n = 0, i = 0; i < select_n; i++) { | 
 | 271 |         if(fd_table[i] != 0) n = i; | 
 | 272 |     } | 
 | 273 |     select_n = n + 1; | 
 | 274 | } | 
 | 275 |  | 
 | 276 | static void fdevent_update(fdevent *fde, unsigned events) | 
 | 277 | { | 
 | 278 |     if(events & FDE_READ) { | 
 | 279 |         FD_SET(fde->fd, &read_fds); | 
 | 280 |     } else { | 
 | 281 |         FD_CLR(fde->fd, &read_fds); | 
 | 282 |     } | 
 | 283 |     if(events & FDE_WRITE) { | 
 | 284 |         FD_SET(fde->fd, &write_fds); | 
 | 285 |     } else { | 
 | 286 |         FD_CLR(fde->fd, &write_fds); | 
 | 287 |     } | 
 | 288 |     if(events & FDE_ERROR) { | 
 | 289 |         FD_SET(fde->fd, &error_fds); | 
 | 290 |     } else { | 
 | 291 |         FD_CLR(fde->fd, &error_fds); | 
 | 292 |     } | 
 | 293 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 294 |     fde->state = (fde->state & FDE_STATEMASK) | events; | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 295 | } | 
 | 296 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 297 | /* Looks at fd_table[] for bad FDs and sets bit in fds. | 
 | 298 | ** Returns the number of bad FDs. | 
 | 299 | */ | 
 | 300 | static int fdevent_fd_check(fd_set *fds) | 
 | 301 | { | 
 | 302 |     int i, n = 0; | 
 | 303 |     fdevent *fde; | 
 | 304 |  | 
 | 305 |     for(i = 0; i < select_n; i++) { | 
 | 306 |         fde = fd_table[i]; | 
 | 307 |         if(fde == 0) continue; | 
 | 308 |         if(fcntl(i, F_GETFL, NULL) < 0) { | 
 | 309 |             FD_SET(i, fds); | 
 | 310 |             n++; | 
 | 311 |             // fde->state |= FDE_DONT_CLOSE; | 
 | 312 |  | 
 | 313 |         } | 
 | 314 |     } | 
 | 315 |     return n; | 
 | 316 | } | 
 | 317 |  | 
 | 318 | #if !DEBUG | 
| Dan Albert | 630b9af | 2014-11-24 23:34:35 -0800 | [diff] [blame] | 319 | static inline void dump_all_fds(const char* /* extra_msg */) {} | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 320 | #else | 
 | 321 | static void dump_all_fds(const char *extra_msg) | 
 | 322 | { | 
 | 323 | int i; | 
 | 324 |     fdevent *fde; | 
 | 325 |     // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank | 
 | 326 |     char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff; | 
 | 327 |     size_t max_chars = FD_SETSIZE * 6 + 1; | 
 | 328 |     int printed_out; | 
 | 329 | #define SAFE_SPRINTF(...)                                                    \ | 
 | 330 |     do {                                                                     \ | 
 | 331 |         printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \ | 
 | 332 |         if (printed_out <= 0) {                                              \ | 
 | 333 |             D("... snprintf failed.\n");                                     \ | 
 | 334 |             return;                                                          \ | 
 | 335 |         }                                                                    \ | 
 | 336 |         if (max_chars < (unsigned int)printed_out) {                         \ | 
 | 337 |             D("... snprintf out of space.\n");                               \ | 
 | 338 |             return;                                                          \ | 
 | 339 |         }                                                                    \ | 
 | 340 |         pb += printed_out;                                                   \ | 
 | 341 |         max_chars -= printed_out;                                            \ | 
 | 342 |     } while(0) | 
 | 343 |  | 
 | 344 |     for(i = 0; i < select_n; i++) { | 
 | 345 |         fde = fd_table[i]; | 
 | 346 |         SAFE_SPRINTF("%d", i); | 
 | 347 |         if(fde == 0) { | 
 | 348 |             SAFE_SPRINTF("? "); | 
 | 349 |             continue; | 
 | 350 |         } | 
 | 351 |         if(fcntl(i, F_GETFL, NULL) < 0) { | 
 | 352 |             SAFE_SPRINTF("b"); | 
 | 353 |         } | 
 | 354 |         SAFE_SPRINTF(" "); | 
 | 355 |     } | 
 | 356 |     D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff); | 
 | 357 | } | 
 | 358 | #endif | 
 | 359 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 360 | static void fdevent_process() | 
 | 361 | { | 
 | 362 |     int i, n; | 
 | 363 |     fdevent *fde; | 
 | 364 |     unsigned events; | 
 | 365 |     fd_set rfd, wfd, efd; | 
 | 366 |  | 
 | 367 |     memcpy(&rfd, &read_fds, sizeof(fd_set)); | 
 | 368 |     memcpy(&wfd, &write_fds, sizeof(fd_set)); | 
 | 369 |     memcpy(&efd, &error_fds, sizeof(fd_set)); | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 370 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 371 |     dump_all_fds("pre select()"); | 
 | 372 |  | 
 | 373 |     n = select(select_n, &rfd, &wfd, &efd, NULL); | 
 | 374 |     int saved_errno = errno; | 
 | 375 |     D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0); | 
 | 376 |  | 
 | 377 |     dump_all_fds("post select()"); | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 378 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 379 |     if(n < 0) { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 380 |         switch(saved_errno) { | 
 | 381 |         case EINTR: return; | 
 | 382 |         case EBADF: | 
 | 383 |             // Can't trust the FD sets after an error. | 
 | 384 |             FD_ZERO(&wfd); | 
 | 385 |             FD_ZERO(&efd); | 
 | 386 |             FD_ZERO(&rfd); | 
 | 387 |             break; | 
 | 388 |         default: | 
 | 389 |             D("Unexpected select() error=%d\n", saved_errno); | 
 | 390 |             return; | 
 | 391 |         } | 
 | 392 |     } | 
 | 393 |     if(n <= 0) { | 
 | 394 |         // We fake a read, as the rest of the code assumes | 
 | 395 |         // that errors will be detected at that point. | 
 | 396 |         n = fdevent_fd_check(&rfd); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 397 |     } | 
 | 398 |  | 
 | 399 |     for(i = 0; (i < select_n) && (n > 0); i++) { | 
 | 400 |         events = 0; | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 401 |         if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; } | 
 | 402 |         if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; } | 
 | 403 |         if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; } | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 404 |  | 
 | 405 |         if(events) { | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 406 |             fde = fd_table[i]; | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 407 |             if(fde == 0) | 
 | 408 |               FATAL("missing fde for fd %d\n", i); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 409 |  | 
 | 410 |             fde->events |= events; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 411 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 412 |             D("got events fde->fd=%d events=%04x, state=%04x\n", | 
 | 413 |                 fde->fd, fde->events, fde->state); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 414 |             if(fde->state & FDE_PENDING) continue; | 
 | 415 |             fde->state |= FDE_PENDING; | 
 | 416 |             fdevent_plist_enqueue(fde); | 
 | 417 |         } | 
 | 418 |     } | 
 | 419 | } | 
 | 420 |  | 
 | 421 | #endif | 
 | 422 |  | 
 | 423 | static void fdevent_register(fdevent *fde) | 
 | 424 | { | 
 | 425 |     if(fde->fd < 0) { | 
 | 426 |         FATAL("bogus negative fd (%d)\n", fde->fd); | 
 | 427 |     } | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 428 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 429 |     if(fde->fd >= fd_table_max) { | 
 | 430 |         int oldmax = fd_table_max; | 
 | 431 |         if(fde->fd > 32000) { | 
 | 432 |             FATAL("bogus huuuuge fd (%d)\n", fde->fd); | 
 | 433 |         } | 
 | 434 |         if(fd_table_max == 0) { | 
 | 435 |             fdevent_init(); | 
 | 436 |             fd_table_max = 256; | 
 | 437 |         } | 
 | 438 |         while(fd_table_max <= fde->fd) { | 
 | 439 |             fd_table_max *= 2; | 
 | 440 |         } | 
| Dan Albert | 630b9af | 2014-11-24 23:34:35 -0800 | [diff] [blame] | 441 |         fd_table = reinterpret_cast<fdevent**>( | 
 | 442 |             realloc(fd_table, sizeof(fdevent*) * fd_table_max)); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 443 |         if(fd_table == 0) { | 
 | 444 |             FATAL("could not expand fd_table to %d entries\n", fd_table_max); | 
 | 445 |         } | 
 | 446 |         memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); | 
 | 447 |     } | 
 | 448 |  | 
 | 449 |     fd_table[fde->fd] = fde; | 
 | 450 | } | 
 | 451 |  | 
 | 452 | static void fdevent_unregister(fdevent *fde) | 
 | 453 | { | 
 | 454 |     if((fde->fd < 0) || (fde->fd >= fd_table_max)) { | 
 | 455 |         FATAL("fd out of range (%d)\n", fde->fd); | 
 | 456 |     } | 
 | 457 |  | 
 | 458 |     if(fd_table[fde->fd] != fde) { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 459 |         FATAL("fd_table out of sync [%d]\n", fde->fd); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 460 |     } | 
 | 461 |  | 
 | 462 |     fd_table[fde->fd] = 0; | 
 | 463 |  | 
 | 464 |     if(!(fde->state & FDE_DONT_CLOSE)) { | 
 | 465 |         dump_fde(fde, "close"); | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 466 |         adb_close(fde->fd); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 467 |     } | 
 | 468 | } | 
 | 469 |  | 
 | 470 | static void fdevent_plist_enqueue(fdevent *node) | 
 | 471 | { | 
 | 472 |     fdevent *list = &list_pending; | 
 | 473 |  | 
 | 474 |     node->next = list; | 
 | 475 |     node->prev = list->prev; | 
 | 476 |     node->prev->next = node; | 
 | 477 |     list->prev = node; | 
 | 478 | } | 
 | 479 |  | 
 | 480 | static void fdevent_plist_remove(fdevent *node) | 
 | 481 | { | 
 | 482 |     node->prev->next = node->next; | 
 | 483 |     node->next->prev = node->prev; | 
 | 484 |     node->next = 0; | 
 | 485 |     node->prev = 0; | 
 | 486 | } | 
 | 487 |  | 
 | 488 | static fdevent *fdevent_plist_dequeue(void) | 
 | 489 | { | 
 | 490 |     fdevent *list = &list_pending; | 
 | 491 |     fdevent *node = list->next; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 492 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 493 |     if(node == list) return 0; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 494 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 495 |     list->next = node->next; | 
 | 496 |     list->next->prev = list; | 
 | 497 |     node->next = 0; | 
 | 498 |     node->prev = 0; | 
 | 499 |  | 
 | 500 |     return node; | 
 | 501 | } | 
 | 502 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 503 | static void fdevent_call_fdfunc(fdevent* fde) | 
 | 504 | { | 
 | 505 |     unsigned events = fde->events; | 
 | 506 |     fde->events = 0; | 
 | 507 |     if(!(fde->state & FDE_PENDING)) return; | 
 | 508 |     fde->state &= (~FDE_PENDING); | 
 | 509 |     dump_fde(fde, "callback"); | 
 | 510 |     fde->func(fde->fd, events, fde->arg); | 
 | 511 | } | 
 | 512 |  | 
| Dan Albert | 630b9af | 2014-11-24 23:34:35 -0800 | [diff] [blame] | 513 | static void fdevent_subproc_event_func(int fd, unsigned ev, | 
 | 514 |                                        void* /* userdata */) | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 515 | { | 
 | 516 |  | 
 | 517 |     D("subproc handling on fd=%d ev=%04x\n", fd, ev); | 
 | 518 |  | 
 | 519 |     // Hook oneself back into the fde's suitable for select() on read. | 
 | 520 |     if((fd < 0) || (fd >= fd_table_max)) { | 
 | 521 |         FATAL("fd %d out of range for fd_table \n", fd); | 
 | 522 |     } | 
 | 523 |     fdevent *fde = fd_table[fd]; | 
 | 524 |     fdevent_add(fde, FDE_READ); | 
 | 525 |  | 
 | 526 |     if(ev & FDE_READ){ | 
 | 527 |       int subproc_fd; | 
 | 528 |  | 
| Dan Albert | cc731cc | 2015-02-24 21:26:58 -0800 | [diff] [blame] | 529 |       if(!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 530 |           FATAL("Failed to read the subproc's fd from fd=%d\n", fd); | 
 | 531 |       } | 
 | 532 |       if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) { | 
 | 533 |           D("subproc_fd %d out of range 0, fd_table_max=%d\n", | 
 | 534 |             subproc_fd, fd_table_max); | 
 | 535 |           return; | 
 | 536 |       } | 
 | 537 |       fdevent *subproc_fde = fd_table[subproc_fd]; | 
 | 538 |       if(!subproc_fde) { | 
 | 539 |           D("subproc_fd %d cleared from fd_table\n", subproc_fd); | 
 | 540 |           return; | 
 | 541 |       } | 
 | 542 |       if(subproc_fde->fd != subproc_fd) { | 
 | 543 |           // Already reallocated? | 
 | 544 |           D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd); | 
 | 545 |           return; | 
 | 546 |       } | 
 | 547 |  | 
 | 548 |       subproc_fde->force_eof = 1; | 
 | 549 |  | 
 | 550 |       int rcount = 0; | 
| JP Abgrall | b40367e | 2011-03-29 12:36:22 -0700 | [diff] [blame] | 551 |       ioctl(subproc_fd, FIONREAD, &rcount); | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 552 |       D("subproc with fd=%d  has rcount=%d err=%d\n", | 
 | 553 |         subproc_fd, rcount, errno); | 
 | 554 |  | 
 | 555 |       if(rcount) { | 
 | 556 |         // If there is data left, it will show up in the select(). | 
 | 557 |         // This works because there is no other thread reading that | 
 | 558 |         // data when in this fd_func(). | 
 | 559 |         return; | 
 | 560 |       } | 
 | 561 |  | 
 | 562 |       D("subproc_fde.state=%04x\n", subproc_fde->state); | 
 | 563 |       subproc_fde->events |= FDE_READ; | 
 | 564 |       if(subproc_fde->state & FDE_PENDING) { | 
 | 565 |         return; | 
 | 566 |       } | 
 | 567 |       subproc_fde->state |= FDE_PENDING; | 
 | 568 |       fdevent_call_fdfunc(subproc_fde); | 
 | 569 |     } | 
 | 570 | } | 
 | 571 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 572 | fdevent *fdevent_create(int fd, fd_func func, void *arg) | 
 | 573 | { | 
 | 574 |     fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); | 
 | 575 |     if(fde == 0) return 0; | 
 | 576 |     fdevent_install(fde, fd, func, arg); | 
 | 577 |     fde->state |= FDE_CREATED; | 
 | 578 |     return fde; | 
 | 579 | } | 
 | 580 |  | 
 | 581 | void fdevent_destroy(fdevent *fde) | 
 | 582 | { | 
 | 583 |     if(fde == 0) return; | 
 | 584 |     if(!(fde->state & FDE_CREATED)) { | 
 | 585 |         FATAL("fde %p not created by fdevent_create()\n", fde); | 
 | 586 |     } | 
 | 587 |     fdevent_remove(fde); | 
| SungHyun Kwon | abb80e0 | 2015-03-03 13:56:42 +0900 | [diff] [blame] | 588 |     free(fde); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 589 | } | 
 | 590 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 591 | void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 592 | { | 
 | 593 |     memset(fde, 0, sizeof(fdevent)); | 
 | 594 |     fde->state = FDE_ACTIVE; | 
 | 595 |     fde->fd = fd; | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 596 |     fde->force_eof = 0; | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 597 |     fde->func = func; | 
 | 598 |     fde->arg = arg; | 
 | 599 |  | 
 | 600 | #ifndef HAVE_WINSOCK | 
 | 601 |     fcntl(fd, F_SETFL, O_NONBLOCK); | 
 | 602 | #endif | 
 | 603 |     fdevent_register(fde); | 
 | 604 |     dump_fde(fde, "connect"); | 
 | 605 |     fdevent_connect(fde); | 
 | 606 |     fde->state |= FDE_ACTIVE; | 
 | 607 | } | 
 | 608 |  | 
 | 609 | void fdevent_remove(fdevent *fde) | 
 | 610 | { | 
 | 611 |     if(fde->state & FDE_PENDING) { | 
 | 612 |         fdevent_plist_remove(fde); | 
 | 613 |     } | 
 | 614 |  | 
 | 615 |     if(fde->state & FDE_ACTIVE) { | 
 | 616 |         fdevent_disconnect(fde); | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 617 |         dump_fde(fde, "disconnect"); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 618 |         fdevent_unregister(fde); | 
 | 619 |     } | 
 | 620 |  | 
 | 621 |     fde->state = 0; | 
 | 622 |     fde->events = 0; | 
 | 623 | } | 
 | 624 |  | 
 | 625 |  | 
 | 626 | void fdevent_set(fdevent *fde, unsigned events) | 
 | 627 | { | 
 | 628 |     events &= FDE_EVENTMASK; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 629 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 630 |     if((fde->state & FDE_EVENTMASK) == events) return; | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 631 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 632 |     if(fde->state & FDE_ACTIVE) { | 
 | 633 |         fdevent_update(fde, events); | 
 | 634 |         dump_fde(fde, "update"); | 
 | 635 |     } | 
 | 636 |  | 
 | 637 |     fde->state = (fde->state & FDE_STATEMASK) | events; | 
 | 638 |  | 
 | 639 |     if(fde->state & FDE_PENDING) { | 
 | 640 |             /* if we're pending, make sure | 
 | 641 |             ** we don't signal an event that | 
 | 642 |             ** is no longer wanted. | 
 | 643 |             */ | 
 | 644 |         fde->events &= (~events); | 
 | 645 |         if(fde->events == 0) { | 
 | 646 |             fdevent_plist_remove(fde); | 
 | 647 |             fde->state &= (~FDE_PENDING); | 
 | 648 |         } | 
 | 649 |     } | 
 | 650 | } | 
 | 651 |  | 
 | 652 | void fdevent_add(fdevent *fde, unsigned events) | 
 | 653 | { | 
 | 654 |     fdevent_set( | 
 | 655 |         fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); | 
 | 656 | } | 
 | 657 |  | 
 | 658 | void fdevent_del(fdevent *fde, unsigned events) | 
 | 659 | { | 
 | 660 |     fdevent_set( | 
 | 661 |         fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); | 
 | 662 | } | 
 | 663 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 664 | void fdevent_subproc_setup() | 
 | 665 | { | 
 | 666 |     int s[2]; | 
 | 667 |  | 
 | 668 |     if(adb_socketpair(s)) { | 
 | 669 |         FATAL("cannot create shell-exit socket-pair\n"); | 
 | 670 |     } | 
| leozwang | cbf0267 | 2014-08-15 09:51:27 -0700 | [diff] [blame] | 671 |     D("socketpair: (%d,%d)", s[0], s[1]); | 
 | 672 |  | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 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 Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 681 | void fdevent_loop() | 
 | 682 | { | 
 | 683 |     fdevent *fde; | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 684 |     fdevent_subproc_setup(); | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 685 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 686 |     for(;;) { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 687 |         D("--- ---- waiting for events\n"); | 
 | 688 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 689 |         fdevent_process(); | 
| David 'Digit' Turner | f6330a2 | 2009-05-18 17:36:28 +0200 | [diff] [blame] | 690 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 691 |         while((fde = fdevent_plist_dequeue())) { | 
| JP Abgrall | 408fa57 | 2011-03-16 15:57:42 -0700 | [diff] [blame] | 692 |             fdevent_call_fdfunc(fde); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 693 |         } | 
 | 694 |     } | 
 | 695 | } |