Home | History | Annotate | Download | only in adb
      1 /* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
      2 **
      3 ** Copyright 2006, Brian Swetland <swetland (at) frotz.net>
      4 **
      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
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     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
     15 ** limitations under the License.
     16 */
     17 
     18 #include <stdlib.h>
     19 #include <stdio.h>
     20 #include <string.h>
     21 #include <unistd.h>
     22 #include <errno.h>
     23 
     24 #include <fcntl.h>
     25 
     26 #include <stdarg.h>
     27 #include <stddef.h>
     28 
     29 #include "fdevent.h"
     30 
     31 #define TRACE(x...) fprintf(stderr,x)
     32 
     33 #define DEBUG 0
     34 
     35 static void fatal(const char *fn, const char *fmt, ...)
     36 {
     37     va_list ap;
     38     va_start(ap, fmt);
     39     fprintf(stderr, "%s:", fn);
     40     vfprintf(stderr, fmt, ap);
     41     va_end(ap);
     42     abort();
     43 }
     44 
     45 #define FATAL(x...) fatal(__FUNCTION__, x)
     46 
     47 #if DEBUG
     48 static void dump_fde(fdevent *fde, const char *info)
     49 {
     50     fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
     51             fde->state & FDE_READ ? 'R' : ' ',
     52             fde->state & FDE_WRITE ? 'W' : ' ',
     53             fde->state & FDE_ERROR ? 'E' : ' ',
     54             info);
     55 }
     56 #else
     57 #define dump_fde(fde, info) do { } while(0)
     58 #endif
     59 
     60 #define FDE_EVENTMASK  0x00ff
     61 #define FDE_STATEMASK  0xff00
     62 
     63 #define FDE_ACTIVE     0x0100
     64 #define FDE_PENDING    0x0200
     65 #define FDE_CREATED    0x0400
     66 
     67 static void fdevent_plist_enqueue(fdevent *node);
     68 static void fdevent_plist_remove(fdevent *node);
     69 static fdevent *fdevent_plist_dequeue(void);
     70 
     71 static fdevent list_pending = {
     72     .next = &list_pending,
     73     .prev = &list_pending,
     74 };
     75 
     76 static fdevent **fd_table = 0;
     77 static int fd_table_max = 0;
     78 
     79 #ifdef CRAPTASTIC
     80 //HAVE_EPOLL
     81 
     82 #include <sys/epoll.h>
     83 
     84 static int epoll_fd = -1;
     85 
     86 static void fdevent_init()
     87 {
     88         /* XXX: what's a good size for the passed in hint? */
     89     epoll_fd = epoll_create(256);
     90 
     91     if(epoll_fd < 0) {
     92         perror("epoll_create() failed");
     93         exit(1);
     94     }
     95 
     96         /* mark for close-on-exec */
     97     fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
     98 }
     99 
    100 static void fdevent_connect(fdevent *fde)
    101 {
    102     struct epoll_event ev;
    103 
    104     memset(&ev, 0, sizeof(ev));
    105     ev.events = 0;
    106     ev.data.ptr = fde;
    107 
    108 #if 0
    109     if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
    110         perror("epoll_ctl() failed\n");
    111         exit(1);
    112     }
    113 #endif
    114 }
    115 
    116 static void fdevent_disconnect(fdevent *fde)
    117 {
    118     struct epoll_event ev;
    119 
    120     memset(&ev, 0, sizeof(ev));
    121     ev.events = 0;
    122     ev.data.ptr = fde;
    123 
    124         /* technically we only need to delete if we
    125         ** were actively monitoring events, but let's
    126         ** be aggressive and do it anyway, just in case
    127         ** something's out of sync
    128         */
    129     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
    130 }
    131 
    132 static void fdevent_update(fdevent *fde, unsigned events)
    133 {
    134     struct epoll_event ev;
    135     int active;
    136 
    137     active = (fde->state & FDE_EVENTMASK) != 0;
    138 
    139     memset(&ev, 0, sizeof(ev));
    140     ev.events = 0;
    141     ev.data.ptr = fde;
    142 
    143     if(events & FDE_READ) ev.events |= EPOLLIN;
    144     if(events & FDE_WRITE) ev.events |= EPOLLOUT;
    145     if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
    146 
    147     fde->state = (fde->state & FDE_STATEMASK) | events;
    148 
    149     if(active) {
    150             /* we're already active. if we're changing to *no*
    151             ** events being monitored, we need to delete, otherwise
    152             ** we need to just modify
    153             */
    154         if(ev.events) {
    155             if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
    156                 perror("epoll_ctl() failed\n");
    157                 exit(1);
    158             }
    159         } else {
    160             if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
    161                 perror("epoll_ctl() failed\n");
    162                 exit(1);
    163             }
    164         }
    165     } else {
    166             /* we're not active.  if we're watching events, we need
    167             ** to add, otherwise we can just do nothing
    168             */
    169         if(ev.events) {
    170             if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
    171                 perror("epoll_ctl() failed\n");
    172                 exit(1);
    173             }
    174         }
    175     }
    176 }
    177 
    178 static void fdevent_process()
    179 {
    180     struct epoll_event events[256];
    181     fdevent *fde;
    182     int i, n;
    183 
    184     n = epoll_wait(epoll_fd, events, 256, -1);
    185 
    186     if(n < 0) {
    187         if(errno == EINTR) return;
    188         perror("epoll_wait");
    189         exit(1);
    190     }
    191 
    192     for(i = 0; i < n; i++) {
    193         struct epoll_event *ev = events + i;
    194         fde = ev->data.ptr;
    195 
    196         if(ev->events & EPOLLIN) {
    197             fde->events |= FDE_READ;
    198         }
    199         if(ev->events & EPOLLOUT) {
    200             fde->events |= FDE_WRITE;
    201         }
    202         if(ev->events & (EPOLLERR | EPOLLHUP)) {
    203             fde->events |= FDE_ERROR;
    204         }
    205         if(fde->events) {
    206             if(fde->state & FDE_PENDING) continue;
    207             fde->state |= FDE_PENDING;
    208             fdevent_plist_enqueue(fde);
    209         }
    210     }
    211 }
    212 
    213 #else /* USE_SELECT */
    214 
    215 #ifdef HAVE_WINSOCK
    216 #include <winsock2.h>
    217 #else
    218 #include <sys/select.h>
    219 #endif
    220 
    221 static fd_set read_fds;
    222 static fd_set write_fds;
    223 static fd_set error_fds;
    224 
    225 static int select_n = 0;
    226 
    227 static void fdevent_init(void)
    228 {
    229     FD_ZERO(&read_fds);
    230     FD_ZERO(&write_fds);
    231     FD_ZERO(&error_fds);
    232 }
    233 
    234 static void fdevent_connect(fdevent *fde)
    235 {
    236     if(fde->fd >= select_n) {
    237         select_n = fde->fd + 1;
    238     }
    239 }
    240 
    241 static void fdevent_disconnect(fdevent *fde)
    242 {
    243     int i, n;
    244 
    245     FD_CLR(fde->fd, &read_fds);
    246     FD_CLR(fde->fd, &write_fds);
    247     FD_CLR(fde->fd, &error_fds);
    248 
    249     for(n = 0, i = 0; i < select_n; i++) {
    250         if(fd_table[i] != 0) n = i;
    251     }
    252     select_n = n + 1;
    253 }
    254 
    255 static void fdevent_update(fdevent *fde, unsigned events)
    256 {
    257     if(events & FDE_READ) {
    258         FD_SET(fde->fd, &read_fds);
    259     } else {
    260         FD_CLR(fde->fd, &read_fds);
    261     }
    262     if(events & FDE_WRITE) {
    263         FD_SET(fde->fd, &write_fds);
    264     } else {
    265         FD_CLR(fde->fd, &write_fds);
    266     }
    267     if(events & FDE_ERROR) {
    268         FD_SET(fde->fd, &error_fds);
    269     } else {
    270         FD_CLR(fde->fd, &error_fds);
    271     }
    272 
    273     fde->state = (fde->state & FDE_STATEMASK) | events;
    274 }
    275 
    276 static void fdevent_process()
    277 {
    278     int i, n;
    279     fdevent *fde;
    280     unsigned events;
    281     fd_set rfd, wfd, efd;
    282 
    283     memcpy(&rfd, &read_fds, sizeof(fd_set));
    284     memcpy(&wfd, &write_fds, sizeof(fd_set));
    285     memcpy(&efd, &error_fds, sizeof(fd_set));
    286 
    287     n = select(select_n, &rfd, &wfd, &efd, 0);
    288 
    289     if(n < 0) {
    290         if(errno == EINTR) return;
    291         perror("select");
    292         return;
    293     }
    294 
    295     for(i = 0; (i < select_n) && (n > 0); i++) {
    296         events = 0;
    297         if(FD_ISSET(i, &rfd)) events |= FDE_READ;
    298         if(FD_ISSET(i, &wfd)) events |= FDE_WRITE;
    299         if(FD_ISSET(i, &efd)) events |= FDE_ERROR;
    300 
    301         if(events) {
    302             n--;
    303 
    304             fde = fd_table[i];
    305             if(fde == 0) FATAL("missing fde for fd %d\n", i);
    306 
    307             fde->events |= events;
    308 
    309             if(fde->state & FDE_PENDING) continue;
    310             fde->state |= FDE_PENDING;
    311             fdevent_plist_enqueue(fde);
    312         }
    313     }
    314 }
    315 
    316 #endif
    317 
    318 static void fdevent_register(fdevent *fde)
    319 {
    320     if(fde->fd < 0) {
    321         FATAL("bogus negative fd (%d)\n", fde->fd);
    322     }
    323 
    324     if(fde->fd >= fd_table_max) {
    325         int oldmax = fd_table_max;
    326         if(fde->fd > 32000) {
    327             FATAL("bogus huuuuge fd (%d)\n", fde->fd);
    328         }
    329         if(fd_table_max == 0) {
    330             fdevent_init();
    331             fd_table_max = 256;
    332         }
    333         while(fd_table_max <= fde->fd) {
    334             fd_table_max *= 2;
    335         }
    336         fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
    337         if(fd_table == 0) {
    338             FATAL("could not expand fd_table to %d entries\n", fd_table_max);
    339         }
    340         memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
    341     }
    342 
    343     fd_table[fde->fd] = fde;
    344 }
    345 
    346 static void fdevent_unregister(fdevent *fde)
    347 {
    348     if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
    349         FATAL("fd out of range (%d)\n", fde->fd);
    350     }
    351 
    352     if(fd_table[fde->fd] != fde) {
    353         FATAL("fd_table out of sync");
    354     }
    355 
    356     fd_table[fde->fd] = 0;
    357 
    358     if(!(fde->state & FDE_DONT_CLOSE)) {
    359         dump_fde(fde, "close");
    360         close(fde->fd);
    361     }
    362 }
    363 
    364 static void fdevent_plist_enqueue(fdevent *node)
    365 {
    366     fdevent *list = &list_pending;
    367 
    368     node->next = list;
    369     node->prev = list->prev;
    370     node->prev->next = node;
    371     list->prev = node;
    372 }
    373 
    374 static void fdevent_plist_remove(fdevent *node)
    375 {
    376     node->prev->next = node->next;
    377     node->next->prev = node->prev;
    378     node->next = 0;
    379     node->prev = 0;
    380 }
    381 
    382 static fdevent *fdevent_plist_dequeue(void)
    383 {
    384     fdevent *list = &list_pending;
    385     fdevent *node = list->next;
    386 
    387     if(node == list) return 0;
    388 
    389     list->next = node->next;
    390     list->next->prev = list;
    391     node->next = 0;
    392     node->prev = 0;
    393 
    394     return node;
    395 }
    396 
    397 fdevent *fdevent_create(int fd, fd_func func, void *arg)
    398 {
    399     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
    400     if(fde == 0) return 0;
    401     fdevent_install(fde, fd, func, arg);
    402     fde->state |= FDE_CREATED;
    403     return fde;
    404 }
    405 
    406 void fdevent_destroy(fdevent *fde)
    407 {
    408     if(fde == 0) return;
    409     if(!(fde->state & FDE_CREATED)) {
    410         FATAL("fde %p not created by fdevent_create()\n", fde);
    411     }
    412     fdevent_remove(fde);
    413 }
    414 
    415 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
    416 {
    417     memset(fde, 0, sizeof(fdevent));
    418     fde->state = FDE_ACTIVE;
    419     fde->fd = fd;
    420     fde->func = func;
    421     fde->arg = arg;
    422 
    423 #ifndef HAVE_WINSOCK
    424     fcntl(fd, F_SETFL, O_NONBLOCK);
    425 #endif
    426     fdevent_register(fde);
    427     dump_fde(fde, "connect");
    428     fdevent_connect(fde);
    429     fde->state |= FDE_ACTIVE;
    430 }
    431 
    432 void fdevent_remove(fdevent *fde)
    433 {
    434     if(fde->state & FDE_PENDING) {
    435         fdevent_plist_remove(fde);
    436     }
    437 
    438     if(fde->state & FDE_ACTIVE) {
    439         fdevent_disconnect(fde);
    440         dump_fde(fde, "disconnect");
    441         fdevent_unregister(fde);
    442     }
    443 
    444     fde->state = 0;
    445     fde->events = 0;
    446 }
    447 
    448 
    449 void fdevent_set(fdevent *fde, unsigned events)
    450 {
    451     events &= FDE_EVENTMASK;
    452 
    453     if((fde->state & FDE_EVENTMASK) == events) return;
    454 
    455     if(fde->state & FDE_ACTIVE) {
    456         fdevent_update(fde, events);
    457         dump_fde(fde, "update");
    458     }
    459 
    460     fde->state = (fde->state & FDE_STATEMASK) | events;
    461 
    462     if(fde->state & FDE_PENDING) {
    463             /* if we're pending, make sure
    464             ** we don't signal an event that
    465             ** is no longer wanted.
    466             */
    467         fde->events &= (~events);
    468         if(fde->events == 0) {
    469             fdevent_plist_remove(fde);
    470             fde->state &= (~FDE_PENDING);
    471         }
    472     }
    473 }
    474 
    475 void fdevent_add(fdevent *fde, unsigned events)
    476 {
    477     fdevent_set(
    478         fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
    479 }
    480 
    481 void fdevent_del(fdevent *fde, unsigned events)
    482 {
    483     fdevent_set(
    484         fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
    485 }
    486 
    487 void fdevent_loop()
    488 {
    489     fdevent *fde;
    490 
    491     for(;;) {
    492 #if DEBUG
    493         fprintf(stderr,"--- ---- waiting for events\n");
    494 #endif
    495         fdevent_process();
    496 
    497         while((fde = fdevent_plist_dequeue())) {
    498             unsigned events = fde->events;
    499             fde->events = 0;
    500             fde->state &= (~FDE_PENDING);
    501             dump_fde(fde, "callback");
    502             fde->func(fde->fd, events, fde->arg);
    503         }
    504     }
    505 }
    506 
    507