Home | History | Annotate | Line # | Download | only in os
      1 /*
      2  * Copyright  2016 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #ifdef HAVE_DIX_CONFIG_H
     24 #include <dix-config.h>
     25 #endif
     26 
     27 #include <X11/X.h>
     28 #include <X11/Xproto.h>
     29 #include <assert.h>
     30 #include <stdlib.h>
     31 #include <unistd.h>
     32 #include "misc.h"               /* for typedef of pointer */
     33 #include "ospoll.h"
     34 #include "list.h"
     35 
     36 #if !HAVE_OSPOLL && defined(HAVE_POLLSET_CREATE)
     37 #include <sys/pollset.h>
     38 #define POLLSET         1
     39 #define HAVE_OSPOLL     1
     40 #endif
     41 
     42 #if !HAVE_OSPOLL && defined(HAVE_PORT_CREATE)
     43 #include <port.h>
     44 #include <poll.h>
     45 #define PORT            1
     46 #define HAVE_OSPOLL     1
     47 #endif
     48 
     49 #if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1)
     50 #include <sys/epoll.h>
     51 #define EPOLL           1
     52 #define HAVE_OSPOLL     1
     53 #endif
     54 
     55 #if !HAVE_OSPOLL
     56 #include "xserver_poll.h"
     57 #define POLL            1
     58 #define HAVE_OSPOLL     1
     59 #endif
     60 
     61 #if POLLSET
     62 
     63 // pollset-based implementation (as seen on AIX)
     64 struct ospollfd {
     65     int                 fd;
     66     int                 xevents;
     67     short               revents;
     68     enum ospoll_trigger trigger;
     69     void                (*callback)(int fd, int xevents, void *data);
     70     void                *data;
     71 };
     72 
     73 struct ospoll {
     74     pollset_t           ps;
     75     struct ospollfd     *fds;
     76     int                 num;
     77     int                 size;
     78 };
     79 
     80 #endif
     81 
     82 #if EPOLL || PORT
     83 
     84 /* epoll-based implementation */
     85 struct ospollfd {
     86     int                 fd;
     87     int                 xevents;
     88     enum ospoll_trigger trigger;
     89     void                (*callback)(int fd, int xevents, void *data);
     90     void                *data;
     91     struct xorg_list    deleted;
     92 };
     93 
     94 struct ospoll {
     95     int                 epoll_fd;
     96     struct ospollfd     **fds;
     97     int                 num;
     98     int                 size;
     99     struct xorg_list    deleted;
    100 };
    101 
    102 #endif
    103 
    104 #if POLL
    105 
    106 /* poll-based implementation */
    107 struct ospollfd {
    108     short               revents;
    109     enum ospoll_trigger trigger;
    110     void                (*callback)(int fd, int revents, void *data);
    111     void                *data;
    112 };
    113 
    114 struct ospoll {
    115     struct pollfd       *fds;
    116     struct ospollfd     *osfds;
    117     int                 num;
    118     int                 size;
    119     Bool                changed;
    120 };
    121 
    122 #endif
    123 
    124 /* Binary search for the specified file descriptor
    125  *
    126  * Returns position if found
    127  * Returns -position - 1 if not found
    128  */
    129 
    130 static int
    131 ospoll_find(struct ospoll *ospoll, int fd)
    132 {
    133     int lo = 0;
    134     int hi = ospoll->num - 1;
    135 
    136     while (lo <= hi) {
    137         int m = (lo + hi) >> 1;
    138 #if EPOLL || PORT
    139         int t = ospoll->fds[m]->fd;
    140 #endif
    141 #if POLL || POLLSET
    142         int t = ospoll->fds[m].fd;
    143 #endif
    144 
    145         if (t < fd)
    146             lo = m + 1;
    147         else if (t > fd)
    148             hi = m - 1;
    149         else
    150             return m;
    151     }
    152     return -(lo + 1);
    153 }
    154 
    155 #if EPOLL || PORT
    156 static void
    157 ospoll_clean_deleted(struct ospoll *ospoll)
    158 {
    159     struct ospollfd     *osfd, *tmp;
    160 
    161     xorg_list_for_each_entry_safe(osfd, tmp, &ospoll->deleted, deleted) {
    162         xorg_list_del(&osfd->deleted);
    163         free(osfd);
    164     }
    165 }
    166 #endif
    167 
    168 /* Insert an element into an array
    169  *
    170  * base: base address of array
    171  * num:  number of elements in the array before the insert
    172  * size: size of each element
    173  * pos:  position to insert at
    174  */
    175 static inline void
    176 array_insert(void *base, size_t num, size_t size, size_t pos)
    177 {
    178     char *b = base;
    179 
    180     memmove(b + (pos+1) * size,
    181             b + pos * size,
    182             (num - pos) * size);
    183 }
    184 
    185 /* Delete an element from an array
    186  *
    187  * base: base address of array
    188  * num:  number of elements in the array before the delete
    189  * size: size of each element
    190  * pos:  position to delete from
    191  */
    192 static inline void
    193 array_delete(void *base, size_t num, size_t size, size_t pos)
    194 {
    195     char *b = base;
    196 
    197     memmove(b + pos * size, b + (pos + 1) * size,
    198             (num - pos - 1) * size);
    199 }
    200 
    201 
    202 struct ospoll *
    203 ospoll_create(void)
    204 {
    205 #if POLLSET
    206     struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
    207 
    208     ospoll->ps = pollset_create(-1);
    209     if (ospoll->ps < 0) {
    210         free (ospoll);
    211         return NULL;
    212     }
    213     return ospoll;
    214 #endif
    215 #if PORT
    216     struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
    217 
    218     ospoll->epoll_fd = port_create();
    219     if (ospoll->epoll_fd < 0) {
    220         free (ospoll);
    221         return NULL;
    222     }
    223     xorg_list_init(&ospoll->deleted);
    224     return ospoll;
    225 #endif
    226 #if EPOLL
    227     struct ospoll       *ospoll = calloc(1, sizeof (struct ospoll));
    228 
    229     ospoll->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    230     if (ospoll->epoll_fd < 0) {
    231         free (ospoll);
    232         return NULL;
    233     }
    234     xorg_list_init(&ospoll->deleted);
    235     return ospoll;
    236 #endif
    237 #if POLL
    238     return calloc(1, sizeof (struct ospoll));
    239 #endif
    240 }
    241 
    242 void
    243 ospoll_destroy(struct ospoll *ospoll)
    244 {
    245 #if POLLSET
    246     if (ospoll) {
    247         assert (ospoll->num == 0);
    248         pollset_destroy(ospoll->ps);
    249         free(ospoll->fds);
    250         free(ospoll);
    251     }
    252 #endif
    253 #if EPOLL || PORT
    254     if (ospoll) {
    255         assert (ospoll->num == 0);
    256         close(ospoll->epoll_fd);
    257         ospoll_clean_deleted(ospoll);
    258         free(ospoll->fds);
    259         free(ospoll);
    260     }
    261 #endif
    262 #if POLL
    263     if (ospoll) {
    264         assert (ospoll->num == 0);
    265         free (ospoll->fds);
    266         free (ospoll->osfds);
    267         free (ospoll);
    268     }
    269 #endif
    270 }
    271 
    272 Bool
    273 ospoll_add(struct ospoll *ospoll, int fd,
    274            enum ospoll_trigger trigger,
    275            void (*callback)(int fd, int xevents, void *data),
    276            void *data)
    277 {
    278     int pos = ospoll_find(ospoll, fd);
    279 #if POLLSET
    280     if (pos < 0) {
    281         if (ospoll->num == ospoll->size) {
    282             struct ospollfd *new_fds;
    283             int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
    284 
    285             new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
    286             if (!new_fds)
    287                 return FALSE;
    288             ospoll->fds = new_fds;
    289             ospoll->size = new_size;
    290         }
    291         pos = -pos - 1;
    292         array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    293         ospoll->num++;
    294 
    295         ospoll->fds[pos].fd = fd;
    296         ospoll->fds[pos].xevents = 0;
    297         ospoll->fds[pos].revents = 0;
    298     }
    299     ospoll->fds[pos].trigger = trigger;
    300     ospoll->fds[pos].callback = callback;
    301     ospoll->fds[pos].data = data;
    302 #endif
    303 #if PORT
    304     struct ospollfd *osfd;
    305 
    306     if (pos < 0) {
    307         osfd = calloc(1, sizeof (struct ospollfd));
    308         if (!osfd)
    309             return FALSE;
    310 
    311         if (ospoll->num >= ospoll->size) {
    312             struct ospollfd **new_fds;
    313             int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
    314 
    315             new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
    316             if (!new_fds) {
    317                 free (osfd);
    318                 return FALSE;
    319             }
    320             ospoll->fds = new_fds;
    321             ospoll->size = new_size;
    322         }
    323 
    324         osfd->fd = fd;
    325         osfd->xevents = 0;
    326 
    327         pos = -pos - 1;
    328         array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    329         ospoll->fds[pos] = osfd;
    330         ospoll->num++;
    331     } else {
    332         osfd = ospoll->fds[pos];
    333     }
    334     osfd->data = data;
    335     osfd->callback = callback;
    336     osfd->trigger = trigger;
    337 #endif
    338 #if EPOLL
    339     struct ospollfd *osfd;
    340 
    341     if (pos < 0) {
    342 
    343         struct epoll_event ev;
    344 
    345         osfd = calloc(1, sizeof (struct ospollfd));
    346         if (!osfd)
    347             return FALSE;
    348 
    349         if (ospoll->num >= ospoll->size) {
    350             struct ospollfd **new_fds;
    351             int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
    352 
    353             new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
    354             if (!new_fds) {
    355                 free (osfd);
    356                 return FALSE;
    357             }
    358             ospoll->fds = new_fds;
    359             ospoll->size = new_size;
    360         }
    361 
    362         ev.events = 0;
    363         ev.data.ptr = osfd;
    364         if (trigger == ospoll_trigger_edge)
    365             ev.events |= EPOLLET;
    366         if (epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
    367             free(osfd);
    368             return FALSE;
    369         }
    370         osfd->fd = fd;
    371         osfd->xevents = 0;
    372 
    373         pos = -pos - 1;
    374         array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    375         ospoll->fds[pos] = osfd;
    376         ospoll->num++;
    377     } else {
    378         osfd = ospoll->fds[pos];
    379     }
    380     osfd->data = data;
    381     osfd->callback = callback;
    382     osfd->trigger = trigger;
    383 #endif
    384 #if POLL
    385     if (pos < 0) {
    386         if (ospoll->num == ospoll->size) {
    387             struct pollfd   *new_fds;
    388             struct ospollfd *new_osfds;
    389             int             new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
    390 
    391             new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
    392             if (!new_fds)
    393                 return FALSE;
    394             ospoll->fds = new_fds;
    395             new_osfds = reallocarray(ospoll->osfds, new_size, sizeof (ospoll->osfds[0]));
    396             if (!new_osfds)
    397                 return FALSE;
    398             ospoll->osfds = new_osfds;
    399             ospoll->size = new_size;
    400         }
    401         pos = -pos - 1;
    402         array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    403         array_insert(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
    404         ospoll->num++;
    405         ospoll->changed = TRUE;
    406 
    407         ospoll->fds[pos].fd = fd;
    408         ospoll->fds[pos].events = 0;
    409         ospoll->fds[pos].revents = 0;
    410         ospoll->osfds[pos].revents = 0;
    411     }
    412     ospoll->osfds[pos].trigger = trigger;
    413     ospoll->osfds[pos].callback = callback;
    414     ospoll->osfds[pos].data = data;
    415 #endif
    416     return TRUE;
    417 }
    418 
    419 void
    420 ospoll_remove(struct ospoll *ospoll, int fd)
    421 {
    422     int pos = ospoll_find(ospoll, fd);
    423 
    424     pos = ospoll_find(ospoll, fd);
    425     if (pos >= 0) {
    426 #if POLLSET
    427         struct ospollfd *osfd = &ospoll->fds[pos];
    428         struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
    429         pollset_ctl(ospoll->ps, &ctl, 1);
    430 
    431         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    432         ospoll->num--;
    433 #endif
    434 #if PORT
    435         struct ospollfd *osfd = ospoll->fds[pos];
    436         port_dissociate(ospoll->epoll_fd, PORT_SOURCE_FD, fd);
    437 
    438         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    439         ospoll->num--;
    440         osfd->callback = NULL;
    441         osfd->data = NULL;
    442         xorg_list_add(&osfd->deleted, &ospoll->deleted);
    443 #endif
    444 #if EPOLL
    445         struct ospollfd *osfd = ospoll->fds[pos];
    446         struct epoll_event ev;
    447         ev.events = 0;
    448         ev.data.ptr = osfd;
    449         (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_DEL, fd, &ev);
    450 
    451         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    452         ospoll->num--;
    453         osfd->callback = NULL;
    454         osfd->data = NULL;
    455         xorg_list_add(&osfd->deleted, &ospoll->deleted);
    456 #endif
    457 #if POLL
    458         array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
    459         array_delete(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
    460         ospoll->num--;
    461         ospoll->changed = TRUE;
    462 #endif
    463     }
    464 }
    465 
    466 #if PORT
    467 static void
    468 epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
    469 {
    470     int events = 0;
    471     if (osfd->xevents & X_NOTIFY_READ)
    472         events |= POLLIN;
    473     if (osfd->xevents & X_NOTIFY_WRITE)
    474         events |= POLLOUT;
    475     port_associate(ospoll->epoll_fd, PORT_SOURCE_FD, osfd->fd, events, osfd);
    476 }
    477 #endif
    478 
    479 #if EPOLL
    480 static void
    481 epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
    482 {
    483     struct epoll_event ev;
    484     ev.events = 0;
    485     if (osfd->xevents & X_NOTIFY_READ)
    486         ev.events |= EPOLLIN;
    487     if (osfd->xevents & X_NOTIFY_WRITE)
    488         ev.events |= EPOLLOUT;
    489     if (osfd->trigger == ospoll_trigger_edge)
    490         ev.events |= EPOLLET;
    491     ev.data.ptr = osfd;
    492     (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_MOD, osfd->fd, &ev);
    493 }
    494 #endif
    495 
    496 void
    497 ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
    498 {
    499     int pos = ospoll_find(ospoll, fd);
    500 
    501     if (pos >= 0) {
    502 #if POLLSET
    503         struct poll_ctl ctl = { .cmd = PS_MOD, .fd = fd };
    504         if (xevents & X_NOTIFY_READ) {
    505             ctl.events |= POLLIN;
    506             ospoll->fds[pos].revents &= ~POLLIN;
    507         }
    508         if (xevents & X_NOTIFY_WRITE) {
    509             ctl.events |= POLLOUT;
    510             ospoll->fds[pos].revents &= ~POLLOUT;
    511         }
    512         pollset_ctl(ospoll->ps, &ctl, 1);
    513         ospoll->fds[pos].xevents |= xevents;
    514 #endif
    515 #if EPOLL || PORT
    516         struct ospollfd *osfd = ospoll->fds[pos];
    517         osfd->xevents |= xevents;
    518         epoll_mod(ospoll, osfd);
    519 #endif
    520 #if POLL
    521         if (xevents & X_NOTIFY_READ) {
    522             ospoll->fds[pos].events |= POLLIN;
    523             ospoll->osfds[pos].revents &= ~POLLIN;
    524         }
    525         if (xevents & X_NOTIFY_WRITE) {
    526             ospoll->fds[pos].events |= POLLOUT;
    527             ospoll->osfds[pos].revents &= ~POLLOUT;
    528         }
    529 #endif
    530     }
    531 }
    532 
    533 void
    534 ospoll_mute(struct ospoll *ospoll, int fd, int xevents)
    535 {
    536     int pos = ospoll_find(ospoll, fd);
    537 
    538     if (pos >= 0) {
    539 #if POLLSET
    540         struct ospollfd *osfd = &ospoll->fds[pos];
    541         osfd->xevents &= ~xevents;
    542         struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
    543         pollset_ctl(ospoll->ps, &ctl, 1);
    544         if (osfd->xevents) {
    545             ctl.cmd = PS_ADD;
    546             if (osfd->xevents & X_NOTIFY_READ) {
    547                 ctl.events |= POLLIN;
    548             }
    549             if (osfd->xevents & X_NOTIFY_WRITE) {
    550                 ctl.events |= POLLOUT;
    551             }
    552             pollset_ctl(ospoll->ps, &ctl, 1);
    553         }
    554 #endif
    555 #if EPOLL || PORT
    556         struct ospollfd *osfd = ospoll->fds[pos];
    557         osfd->xevents &= ~xevents;
    558         epoll_mod(ospoll, osfd);
    559 #endif
    560 #if POLL
    561         if (xevents & X_NOTIFY_READ)
    562             ospoll->fds[pos].events &= ~POLLIN;
    563         if (xevents & X_NOTIFY_WRITE)
    564             ospoll->fds[pos].events &= ~POLLOUT;
    565 #endif
    566     }
    567 }
    568 
    569 
    570 int
    571 ospoll_wait(struct ospoll *ospoll, int timeout)
    572 {
    573     int nready;
    574 #if POLLSET
    575 #define MAX_EVENTS      256
    576     struct pollfd events[MAX_EVENTS];
    577 
    578     nready = pollset_poll(ospoll->ps, events, MAX_EVENTS, timeout);
    579     for (int i = 0; i < nready; i++) {
    580         struct pollfd *ev = &events[i];
    581         int pos = ospoll_find(ospoll, ev->fd);
    582         struct ospollfd *osfd = &ospoll->fds[pos];
    583         short revents = ev->revents;
    584         short oldevents = osfd->revents;
    585 
    586         osfd->revents = (revents & (POLLIN|POLLOUT));
    587         if (osfd->trigger == ospoll_trigger_edge)
    588             revents &= ~oldevents;
    589         if (revents) {
    590             int xevents = 0;
    591             if (revents & POLLIN)
    592                 xevents |= X_NOTIFY_READ;
    593             if (revents & POLLOUT)
    594                 xevents |= X_NOTIFY_WRITE;
    595             if (revents & (~(POLLIN|POLLOUT)))
    596                 xevents |= X_NOTIFY_ERROR;
    597             osfd->callback(osfd->fd, xevents, osfd->data);
    598         }
    599     }
    600 #endif
    601 #if PORT
    602 #define MAX_EVENTS      256
    603     port_event_t events[MAX_EVENTS];
    604     uint_t nget = 1;
    605     timespec_t port_timeout = {
    606         .tv_sec = timeout / 1000,
    607         .tv_nsec = (timeout % 1000) * 1000000
    608     };
    609 
    610     nready = 0;
    611     if (port_getn(ospoll->epoll_fd, events, MAX_EVENTS, &nget, &port_timeout)
    612         == 0) {
    613         nready = nget;
    614     }
    615     for (int i = 0; i < nready; i++) {
    616         port_event_t *ev = &events[i];
    617         struct ospollfd *osfd = ev->portev_user;
    618         uint32_t revents = ev->portev_events;
    619         int xevents = 0;
    620 
    621         if (revents & POLLIN)
    622             xevents |= X_NOTIFY_READ;
    623         if (revents & POLLOUT)
    624             xevents |= X_NOTIFY_WRITE;
    625         if (revents & (~(POLLIN|POLLOUT)))
    626             xevents |= X_NOTIFY_ERROR;
    627 
    628         if (osfd->callback)
    629             osfd->callback(osfd->fd, xevents, osfd->data);
    630 
    631         if (osfd->trigger == ospoll_trigger_level &&
    632             !xorg_list_is_empty(&osfd->deleted)) {
    633             epoll_mod(ospoll, osfd);
    634         }
    635     }
    636     ospoll_clean_deleted(ospoll);
    637 #endif
    638 #if EPOLL
    639 #define MAX_EVENTS      256
    640     struct epoll_event events[MAX_EVENTS];
    641     int i;
    642 
    643     nready = epoll_wait(ospoll->epoll_fd, events, MAX_EVENTS, timeout);
    644     for (i = 0; i < nready; i++) {
    645         struct epoll_event *ev = &events[i];
    646         struct ospollfd *osfd = ev->data.ptr;
    647         uint32_t revents = ev->events;
    648         int xevents = 0;
    649 
    650         if (revents & EPOLLIN)
    651             xevents |= X_NOTIFY_READ;
    652         if (revents & EPOLLOUT)
    653             xevents |= X_NOTIFY_WRITE;
    654         if (revents & (~(EPOLLIN|EPOLLOUT)))
    655             xevents |= X_NOTIFY_ERROR;
    656 
    657         if (osfd->callback)
    658             osfd->callback(osfd->fd, xevents, osfd->data);
    659     }
    660     ospoll_clean_deleted(ospoll);
    661 #endif
    662 #if POLL
    663     nready = xserver_poll(ospoll->fds, ospoll->num, timeout);
    664     ospoll->changed = FALSE;
    665     if (nready > 0) {
    666         int f;
    667         for (f = 0; f < ospoll->num; f++) {
    668             short revents = ospoll->fds[f].revents;
    669             short oldevents = ospoll->osfds[f].revents;
    670 
    671             ospoll->osfds[f].revents = (revents & (POLLIN|POLLOUT));
    672             if (ospoll->osfds[f].trigger == ospoll_trigger_edge)
    673                 revents &= ~oldevents;
    674             if (revents) {
    675                 int    xevents = 0;
    676                 if (revents & POLLIN)
    677                     xevents |= X_NOTIFY_READ;
    678                 if (revents & POLLOUT)
    679                     xevents |= X_NOTIFY_WRITE;
    680                 if (revents & (~(POLLIN|POLLOUT)))
    681                     xevents |= X_NOTIFY_ERROR;
    682                 ospoll->osfds[f].callback(ospoll->fds[f].fd, xevents,
    683                                           ospoll->osfds[f].data);
    684 
    685                 /* Check to see if the arrays have changed, and just go back
    686                  * around again
    687                  */
    688                 if (ospoll->changed)
    689                     break;
    690             }
    691         }
    692     }
    693 #endif
    694     return nready;
    695 }
    696 
    697 void
    698 ospoll_reset_events(struct ospoll *ospoll, int fd)
    699 {
    700 #if POLLSET
    701     int pos = ospoll_find(ospoll, fd);
    702 
    703     if (pos < 0)
    704         return;
    705 
    706     ospoll->fds[pos].revents = 0;
    707 #endif
    708 #if PORT
    709     int pos = ospoll_find(ospoll, fd);
    710 
    711     if (pos < 0)
    712         return;
    713 
    714     epoll_mod(ospoll, ospoll->fds[pos]);
    715 #endif
    716 #if POLL
    717     int pos = ospoll_find(ospoll, fd);
    718 
    719     if (pos < 0)
    720         return;
    721 
    722     ospoll->osfds[pos].revents = 0;
    723 #endif
    724 }
    725 
    726 void *
    727 ospoll_data(struct ospoll *ospoll, int fd)
    728 {
    729     int pos = ospoll_find(ospoll, fd);
    730 
    731     if (pos < 0)
    732         return NULL;
    733 #if POLLSET
    734     return ospoll->fds[pos].data;
    735 #endif
    736 #if EPOLL || PORT
    737     return ospoll->fds[pos]->data;
    738 #endif
    739 #if POLL
    740     return ospoll->osfds[pos].data;
    741 #endif
    742 }
    743