11b5d61b8Smrg/*
21b5d61b8Smrg * Copyright © 2016 Keith Packard
31b5d61b8Smrg *
41b5d61b8Smrg * Permission to use, copy, modify, distribute, and sell this software and its
51b5d61b8Smrg * documentation for any purpose is hereby granted without fee, provided that
61b5d61b8Smrg * the above copyright notice appear in all copies and that both that copyright
71b5d61b8Smrg * notice and this permission notice appear in supporting documentation, and
81b5d61b8Smrg * that the name of the copyright holders not be used in advertising or
91b5d61b8Smrg * publicity pertaining to distribution of the software without specific,
101b5d61b8Smrg * written prior permission.  The copyright holders make no representations
111b5d61b8Smrg * about the suitability of this software for any purpose.  It is provided "as
121b5d61b8Smrg * is" without express or implied warranty.
131b5d61b8Smrg *
141b5d61b8Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
151b5d61b8Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
161b5d61b8Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
171b5d61b8Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
181b5d61b8Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
191b5d61b8Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
201b5d61b8Smrg * OF THIS SOFTWARE.
211b5d61b8Smrg */
221b5d61b8Smrg
231b5d61b8Smrg#ifdef HAVE_DIX_CONFIG_H
241b5d61b8Smrg#include <dix-config.h>
251b5d61b8Smrg#endif
261b5d61b8Smrg
271b5d61b8Smrg#include <X11/X.h>
281b5d61b8Smrg#include <X11/Xproto.h>
291b5d61b8Smrg#include <stdlib.h>
301b5d61b8Smrg#include <unistd.h>
311b5d61b8Smrg#include "misc.h"               /* for typedef of pointer */
321b5d61b8Smrg#include "ospoll.h"
331b5d61b8Smrg#include "list.h"
341b5d61b8Smrg
351b5d61b8Smrg#if !HAVE_OSPOLL && defined(HAVE_POLLSET_CREATE)
361b5d61b8Smrg#include <sys/pollset.h>
371b5d61b8Smrg#define POLLSET         1
381b5d61b8Smrg#define HAVE_OSPOLL     1
391b5d61b8Smrg#endif
401b5d61b8Smrg
411b5d61b8Smrg#if !HAVE_OSPOLL && defined(HAVE_PORT_CREATE)
421b5d61b8Smrg#include <port.h>
435a7dfde8Smrg#include <poll.h>
441b5d61b8Smrg#define PORT            1
451b5d61b8Smrg#define HAVE_OSPOLL     1
461b5d61b8Smrg#endif
471b5d61b8Smrg
481b5d61b8Smrg#if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1)
491b5d61b8Smrg#include <sys/epoll.h>
501b5d61b8Smrg#define EPOLL           1
511b5d61b8Smrg#define HAVE_OSPOLL     1
521b5d61b8Smrg#endif
531b5d61b8Smrg
541b5d61b8Smrg#if !HAVE_OSPOLL
551b5d61b8Smrg#include "xserver_poll.h"
561b5d61b8Smrg#define POLL            1
571b5d61b8Smrg#define HAVE_OSPOLL     1
581b5d61b8Smrg#endif
591b5d61b8Smrg
601b5d61b8Smrg#if POLLSET
611b5d61b8Smrg
621b5d61b8Smrg// pollset-based implementation (as seen on AIX)
631b5d61b8Smrgstruct ospollfd {
641b5d61b8Smrg    int                 fd;
651b5d61b8Smrg    int                 xevents;
661b5d61b8Smrg    short               revents;
671b5d61b8Smrg    enum ospoll_trigger trigger;
681b5d61b8Smrg    void                (*callback)(int fd, int xevents, void *data);
691b5d61b8Smrg    void                *data;
701b5d61b8Smrg};
711b5d61b8Smrg
721b5d61b8Smrgstruct ospoll {
731b5d61b8Smrg    pollset_t           ps;
741b5d61b8Smrg    struct ospollfd     *fds;
751b5d61b8Smrg    int                 num;
761b5d61b8Smrg    int                 size;
771b5d61b8Smrg};
781b5d61b8Smrg
791b5d61b8Smrg#endif
801b5d61b8Smrg
811b5d61b8Smrg#if EPOLL || PORT
821b5d61b8Smrg
831b5d61b8Smrg/* epoll-based implementation */
841b5d61b8Smrgstruct ospollfd {
851b5d61b8Smrg    int                 fd;
861b5d61b8Smrg    int                 xevents;
871b5d61b8Smrg    enum ospoll_trigger trigger;
881b5d61b8Smrg    void                (*callback)(int fd, int xevents, void *data);
891b5d61b8Smrg    void                *data;
901b5d61b8Smrg    struct xorg_list    deleted;
911b5d61b8Smrg};
921b5d61b8Smrg
931b5d61b8Smrgstruct ospoll {
941b5d61b8Smrg    int                 epoll_fd;
951b5d61b8Smrg    struct ospollfd     **fds;
961b5d61b8Smrg    int                 num;
971b5d61b8Smrg    int                 size;
981b5d61b8Smrg    struct xorg_list    deleted;
991b5d61b8Smrg};
1001b5d61b8Smrg
1011b5d61b8Smrg#endif
1021b5d61b8Smrg
1031b5d61b8Smrg#if POLL
1041b5d61b8Smrg
1051b5d61b8Smrg/* poll-based implementation */
1061b5d61b8Smrgstruct ospollfd {
1071b5d61b8Smrg    short               revents;
1081b5d61b8Smrg    enum ospoll_trigger trigger;
1091b5d61b8Smrg    void                (*callback)(int fd, int revents, void *data);
1101b5d61b8Smrg    void                *data;
1111b5d61b8Smrg};
1121b5d61b8Smrg
1131b5d61b8Smrgstruct ospoll {
1141b5d61b8Smrg    struct pollfd       *fds;
1151b5d61b8Smrg    struct ospollfd     *osfds;
1161b5d61b8Smrg    int                 num;
1171b5d61b8Smrg    int                 size;
1181b5d61b8Smrg    Bool                changed;
1191b5d61b8Smrg};
1201b5d61b8Smrg
1211b5d61b8Smrg#endif
1221b5d61b8Smrg
1231b5d61b8Smrg/* Binary search for the specified file descriptor
1241b5d61b8Smrg *
1251b5d61b8Smrg * Returns position if found
1261b5d61b8Smrg * Returns -position - 1 if not found
1271b5d61b8Smrg */
1281b5d61b8Smrg
1291b5d61b8Smrgstatic int
1301b5d61b8Smrgospoll_find(struct ospoll *ospoll, int fd)
1311b5d61b8Smrg{
1321b5d61b8Smrg    int lo = 0;
1331b5d61b8Smrg    int hi = ospoll->num - 1;
1341b5d61b8Smrg
1351b5d61b8Smrg    while (lo <= hi) {
1361b5d61b8Smrg        int m = (lo + hi) >> 1;
1371b5d61b8Smrg#if EPOLL || PORT
1381b5d61b8Smrg        int t = ospoll->fds[m]->fd;
1391b5d61b8Smrg#endif
1401b5d61b8Smrg#if POLL || POLLSET
1411b5d61b8Smrg        int t = ospoll->fds[m].fd;
1421b5d61b8Smrg#endif
1431b5d61b8Smrg
1441b5d61b8Smrg        if (t < fd)
1451b5d61b8Smrg            lo = m + 1;
1461b5d61b8Smrg        else if (t > fd)
1471b5d61b8Smrg            hi = m - 1;
1481b5d61b8Smrg        else
1491b5d61b8Smrg            return m;
1501b5d61b8Smrg    }
1511b5d61b8Smrg    return -(lo + 1);
1521b5d61b8Smrg}
1531b5d61b8Smrg
1541b5d61b8Smrg#if EPOLL || PORT
1551b5d61b8Smrgstatic void
1561b5d61b8Smrgospoll_clean_deleted(struct ospoll *ospoll)
1571b5d61b8Smrg{
1581b5d61b8Smrg    struct ospollfd     *osfd, *tmp;
1591b5d61b8Smrg
1601b5d61b8Smrg    xorg_list_for_each_entry_safe(osfd, tmp, &ospoll->deleted, deleted) {
1611b5d61b8Smrg        xorg_list_del(&osfd->deleted);
1621b5d61b8Smrg        free(osfd);
1631b5d61b8Smrg    }
1641b5d61b8Smrg}
1651b5d61b8Smrg#endif
1661b5d61b8Smrg
1671b5d61b8Smrg/* Insert an element into an array
1681b5d61b8Smrg *
1691b5d61b8Smrg * base: base address of array
1701b5d61b8Smrg * num:  number of elements in the array before the insert
1711b5d61b8Smrg * size: size of each element
1721b5d61b8Smrg * pos:  position to insert at
1731b5d61b8Smrg */
1741b5d61b8Smrgstatic inline void
1751b5d61b8Smrgarray_insert(void *base, size_t num, size_t size, size_t pos)
1761b5d61b8Smrg{
1771b5d61b8Smrg    char *b = base;
1781b5d61b8Smrg
1791b5d61b8Smrg    memmove(b + (pos+1) * size,
1801b5d61b8Smrg            b + pos * size,
1811b5d61b8Smrg            (num - pos) * size);
1821b5d61b8Smrg}
1831b5d61b8Smrg
1841b5d61b8Smrg/* Delete an element from an array
1851b5d61b8Smrg *
1861b5d61b8Smrg * base: base address of array
1871b5d61b8Smrg * num:  number of elements in the array before the delete
1881b5d61b8Smrg * size: size of each element
1891b5d61b8Smrg * pos:  position to delete from
1901b5d61b8Smrg */
1911b5d61b8Smrgstatic inline void
1921b5d61b8Smrgarray_delete(void *base, size_t num, size_t size, size_t pos)
1931b5d61b8Smrg{
1941b5d61b8Smrg    char *b = base;
1951b5d61b8Smrg
1961b5d61b8Smrg    memmove(b + pos * size, b + (pos + 1) * size,
1971b5d61b8Smrg            (num - pos - 1) * size);
1981b5d61b8Smrg}
1991b5d61b8Smrg
2001b5d61b8Smrg
2011b5d61b8Smrgstruct ospoll *
2021b5d61b8Smrgospoll_create(void)
2031b5d61b8Smrg{
2041b5d61b8Smrg#if POLLSET
2051b5d61b8Smrg    struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
2061b5d61b8Smrg
2071b5d61b8Smrg    ospoll->ps = pollset_create(-1);
2081b5d61b8Smrg    if (ospoll->ps < 0) {
2091b5d61b8Smrg        free (ospoll);
2101b5d61b8Smrg        return NULL;
2111b5d61b8Smrg    }
2121b5d61b8Smrg    return ospoll;
2131b5d61b8Smrg#endif
2141b5d61b8Smrg#if PORT
2151b5d61b8Smrg    struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
2161b5d61b8Smrg
2171b5d61b8Smrg    ospoll->epoll_fd = port_create();
2181b5d61b8Smrg    if (ospoll->epoll_fd < 0) {
2191b5d61b8Smrg        free (ospoll);
2201b5d61b8Smrg        return NULL;
2211b5d61b8Smrg    }
2221b5d61b8Smrg    xorg_list_init(&ospoll->deleted);
2231b5d61b8Smrg    return ospoll;
2241b5d61b8Smrg#endif
2251b5d61b8Smrg#if EPOLL
2261b5d61b8Smrg    struct ospoll       *ospoll = calloc(1, sizeof (struct ospoll));
2271b5d61b8Smrg
2281b5d61b8Smrg    ospoll->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
2291b5d61b8Smrg    if (ospoll->epoll_fd < 0) {
2301b5d61b8Smrg        free (ospoll);
2311b5d61b8Smrg        return NULL;
2321b5d61b8Smrg    }
2331b5d61b8Smrg    xorg_list_init(&ospoll->deleted);
2341b5d61b8Smrg    return ospoll;
2351b5d61b8Smrg#endif
2361b5d61b8Smrg#if POLL
2371b5d61b8Smrg    return calloc(1, sizeof (struct ospoll));
2381b5d61b8Smrg#endif
2391b5d61b8Smrg}
2401b5d61b8Smrg
2411b5d61b8Smrgvoid
2421b5d61b8Smrgospoll_destroy(struct ospoll *ospoll)
2431b5d61b8Smrg{
2441b5d61b8Smrg#if POLLSET
2451b5d61b8Smrg    if (ospoll) {
2461b5d61b8Smrg        assert (ospoll->num == 0);
2471b5d61b8Smrg        pollset_destroy(ospoll->ps);
2481b5d61b8Smrg        free(ospoll->fds);
2491b5d61b8Smrg        free(ospoll);
2501b5d61b8Smrg    }
2511b5d61b8Smrg#endif
2521b5d61b8Smrg#if EPOLL || PORT
2531b5d61b8Smrg    if (ospoll) {
2541b5d61b8Smrg        assert (ospoll->num == 0);
2551b5d61b8Smrg        close(ospoll->epoll_fd);
2561b5d61b8Smrg        ospoll_clean_deleted(ospoll);
2571b5d61b8Smrg        free(ospoll->fds);
2581b5d61b8Smrg        free(ospoll);
2591b5d61b8Smrg    }
2601b5d61b8Smrg#endif
2611b5d61b8Smrg#if POLL
2621b5d61b8Smrg    if (ospoll) {
2631b5d61b8Smrg        assert (ospoll->num == 0);
2641b5d61b8Smrg        free (ospoll->fds);
2651b5d61b8Smrg        free (ospoll->osfds);
2661b5d61b8Smrg        free (ospoll);
2671b5d61b8Smrg    }
2681b5d61b8Smrg#endif
2691b5d61b8Smrg}
2701b5d61b8Smrg
2711b5d61b8SmrgBool
2721b5d61b8Smrgospoll_add(struct ospoll *ospoll, int fd,
2731b5d61b8Smrg           enum ospoll_trigger trigger,
2741b5d61b8Smrg           void (*callback)(int fd, int xevents, void *data),
2751b5d61b8Smrg           void *data)
2761b5d61b8Smrg{
2771b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
2781b5d61b8Smrg#if POLLSET
2791b5d61b8Smrg    if (pos < 0) {
2801b5d61b8Smrg        if (ospoll->num == ospoll->size) {
2811b5d61b8Smrg            struct ospollfd *new_fds;
2821b5d61b8Smrg            int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
2831b5d61b8Smrg
2841b5d61b8Smrg            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
2851b5d61b8Smrg            if (!new_fds)
2861b5d61b8Smrg                return FALSE;
2871b5d61b8Smrg            ospoll->fds = new_fds;
2881b5d61b8Smrg            ospoll->size = new_size;
2891b5d61b8Smrg        }
2901b5d61b8Smrg        pos = -pos - 1;
2911b5d61b8Smrg        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
2921b5d61b8Smrg        ospoll->num++;
2931b5d61b8Smrg
2941b5d61b8Smrg        ospoll->fds[pos].fd = fd;
2951b5d61b8Smrg        ospoll->fds[pos].xevents = 0;
2961b5d61b8Smrg        ospoll->fds[pos].revents = 0;
2971b5d61b8Smrg    }
2981b5d61b8Smrg    ospoll->fds[pos].trigger = trigger;
2991b5d61b8Smrg    ospoll->fds[pos].callback = callback;
3001b5d61b8Smrg    ospoll->fds[pos].data = data;
3011b5d61b8Smrg#endif
3021b5d61b8Smrg#if PORT
3031b5d61b8Smrg    struct ospollfd *osfd;
3041b5d61b8Smrg
3051b5d61b8Smrg    if (pos < 0) {
3061b5d61b8Smrg        osfd = calloc(1, sizeof (struct ospollfd));
3071b5d61b8Smrg        if (!osfd)
3081b5d61b8Smrg            return FALSE;
3091b5d61b8Smrg
3101b5d61b8Smrg        if (ospoll->num >= ospoll->size) {
3111b5d61b8Smrg            struct ospollfd **new_fds;
3121b5d61b8Smrg            int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
3131b5d61b8Smrg
3141b5d61b8Smrg            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
3151b5d61b8Smrg            if (!new_fds) {
3161b5d61b8Smrg                free (osfd);
3171b5d61b8Smrg                return FALSE;
3181b5d61b8Smrg            }
3191b5d61b8Smrg            ospoll->fds = new_fds;
3201b5d61b8Smrg            ospoll->size = new_size;
3211b5d61b8Smrg        }
3221b5d61b8Smrg
3231b5d61b8Smrg        osfd->fd = fd;
3241b5d61b8Smrg        osfd->xevents = 0;
3251b5d61b8Smrg
3261b5d61b8Smrg        pos = -pos - 1;
3271b5d61b8Smrg        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
3281b5d61b8Smrg        ospoll->fds[pos] = osfd;
3291b5d61b8Smrg        ospoll->num++;
3301b5d61b8Smrg    } else {
3311b5d61b8Smrg        osfd = ospoll->fds[pos];
3321b5d61b8Smrg    }
3331b5d61b8Smrg    osfd->data = data;
3341b5d61b8Smrg    osfd->callback = callback;
3351b5d61b8Smrg    osfd->trigger = trigger;
3361b5d61b8Smrg#endif
3371b5d61b8Smrg#if EPOLL
3381b5d61b8Smrg    struct ospollfd *osfd;
3391b5d61b8Smrg
3401b5d61b8Smrg    if (pos < 0) {
3411b5d61b8Smrg
3421b5d61b8Smrg        struct epoll_event ev;
3431b5d61b8Smrg
3441b5d61b8Smrg        osfd = calloc(1, sizeof (struct ospollfd));
3451b5d61b8Smrg        if (!osfd)
3461b5d61b8Smrg            return FALSE;
3471b5d61b8Smrg
3481b5d61b8Smrg        if (ospoll->num >= ospoll->size) {
3491b5d61b8Smrg            struct ospollfd **new_fds;
3501b5d61b8Smrg            int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
3511b5d61b8Smrg
3521b5d61b8Smrg            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
3531b5d61b8Smrg            if (!new_fds) {
3541b5d61b8Smrg                free (osfd);
3551b5d61b8Smrg                return FALSE;
3561b5d61b8Smrg            }
3571b5d61b8Smrg            ospoll->fds = new_fds;
3581b5d61b8Smrg            ospoll->size = new_size;
3591b5d61b8Smrg        }
3601b5d61b8Smrg
3611b5d61b8Smrg        ev.events = 0;
3621b5d61b8Smrg        ev.data.ptr = osfd;
3631b5d61b8Smrg        if (trigger == ospoll_trigger_edge)
3641b5d61b8Smrg            ev.events |= EPOLLET;
3651b5d61b8Smrg        if (epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
3661b5d61b8Smrg            free(osfd);
3671b5d61b8Smrg            return FALSE;
3681b5d61b8Smrg        }
3691b5d61b8Smrg        osfd->fd = fd;
3701b5d61b8Smrg        osfd->xevents = 0;
3711b5d61b8Smrg
3721b5d61b8Smrg        pos = -pos - 1;
3731b5d61b8Smrg        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
3741b5d61b8Smrg        ospoll->fds[pos] = osfd;
3751b5d61b8Smrg        ospoll->num++;
3761b5d61b8Smrg    } else {
3771b5d61b8Smrg        osfd = ospoll->fds[pos];
3781b5d61b8Smrg    }
3791b5d61b8Smrg    osfd->data = data;
3801b5d61b8Smrg    osfd->callback = callback;
3811b5d61b8Smrg    osfd->trigger = trigger;
3821b5d61b8Smrg#endif
3831b5d61b8Smrg#if POLL
3841b5d61b8Smrg    if (pos < 0) {
3851b5d61b8Smrg        if (ospoll->num == ospoll->size) {
3861b5d61b8Smrg            struct pollfd   *new_fds;
3871b5d61b8Smrg            struct ospollfd *new_osfds;
3881b5d61b8Smrg            int             new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
3891b5d61b8Smrg
3901b5d61b8Smrg            new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
3911b5d61b8Smrg            if (!new_fds)
3921b5d61b8Smrg                return FALSE;
3931b5d61b8Smrg            ospoll->fds = new_fds;
3941b5d61b8Smrg            new_osfds = reallocarray(ospoll->osfds, new_size, sizeof (ospoll->osfds[0]));
3951b5d61b8Smrg            if (!new_osfds)
3961b5d61b8Smrg                return FALSE;
3971b5d61b8Smrg            ospoll->osfds = new_osfds;
3981b5d61b8Smrg            ospoll->size = new_size;
3991b5d61b8Smrg        }
4001b5d61b8Smrg        pos = -pos - 1;
4011b5d61b8Smrg        array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
4021b5d61b8Smrg        array_insert(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
4031b5d61b8Smrg        ospoll->num++;
4041b5d61b8Smrg        ospoll->changed = TRUE;
4051b5d61b8Smrg
4061b5d61b8Smrg        ospoll->fds[pos].fd = fd;
4071b5d61b8Smrg        ospoll->fds[pos].events = 0;
4081b5d61b8Smrg        ospoll->fds[pos].revents = 0;
4091b5d61b8Smrg        ospoll->osfds[pos].revents = 0;
4101b5d61b8Smrg    }
4111b5d61b8Smrg    ospoll->osfds[pos].trigger = trigger;
4121b5d61b8Smrg    ospoll->osfds[pos].callback = callback;
4131b5d61b8Smrg    ospoll->osfds[pos].data = data;
4141b5d61b8Smrg#endif
4151b5d61b8Smrg    return TRUE;
4161b5d61b8Smrg}
4171b5d61b8Smrg
4181b5d61b8Smrgvoid
4191b5d61b8Smrgospoll_remove(struct ospoll *ospoll, int fd)
4201b5d61b8Smrg{
4211b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
4221b5d61b8Smrg
4231b5d61b8Smrg    pos = ospoll_find(ospoll, fd);
4241b5d61b8Smrg    if (pos >= 0) {
4251b5d61b8Smrg#if POLLSET
4261b5d61b8Smrg        struct ospollfd *osfd = &ospoll->fds[pos];
4271b5d61b8Smrg        struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
4281b5d61b8Smrg        pollset_ctl(ospoll->ps, &ctl, 1);
4291b5d61b8Smrg
4301b5d61b8Smrg        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
4311b5d61b8Smrg        ospoll->num--;
4321b5d61b8Smrg#endif
4331b5d61b8Smrg#if PORT
4341b5d61b8Smrg        struct ospollfd *osfd = ospoll->fds[pos];
4351b5d61b8Smrg        port_dissociate(ospoll->epoll_fd, PORT_SOURCE_FD, fd);
4361b5d61b8Smrg
4371b5d61b8Smrg        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
4381b5d61b8Smrg        ospoll->num--;
4391b5d61b8Smrg        osfd->callback = NULL;
4401b5d61b8Smrg        osfd->data = NULL;
4411b5d61b8Smrg        xorg_list_add(&osfd->deleted, &ospoll->deleted);
4421b5d61b8Smrg#endif
4431b5d61b8Smrg#if EPOLL
4441b5d61b8Smrg        struct ospollfd *osfd = ospoll->fds[pos];
4451b5d61b8Smrg        struct epoll_event ev;
4461b5d61b8Smrg        ev.events = 0;
4471b5d61b8Smrg        ev.data.ptr = osfd;
4481b5d61b8Smrg        (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_DEL, fd, &ev);
4491b5d61b8Smrg
4501b5d61b8Smrg        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
4511b5d61b8Smrg        ospoll->num--;
4521b5d61b8Smrg        osfd->callback = NULL;
4531b5d61b8Smrg        osfd->data = NULL;
4541b5d61b8Smrg        xorg_list_add(&osfd->deleted, &ospoll->deleted);
4551b5d61b8Smrg#endif
4561b5d61b8Smrg#if POLL
4571b5d61b8Smrg        array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
4581b5d61b8Smrg        array_delete(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
4591b5d61b8Smrg        ospoll->num--;
4601b5d61b8Smrg        ospoll->changed = TRUE;
4611b5d61b8Smrg#endif
4621b5d61b8Smrg    }
4631b5d61b8Smrg}
4641b5d61b8Smrg
4651b5d61b8Smrg#if PORT
4661b5d61b8Smrgstatic void
4671b5d61b8Smrgepoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
4681b5d61b8Smrg{
4691b5d61b8Smrg    int events = 0;
4701b5d61b8Smrg    if (osfd->xevents & X_NOTIFY_READ)
4715a7dfde8Smrg        events |= POLLIN;
4721b5d61b8Smrg    if (osfd->xevents & X_NOTIFY_WRITE)
4735a7dfde8Smrg        events |= POLLOUT;
4745a7dfde8Smrg    port_associate(ospoll->epoll_fd, PORT_SOURCE_FD, osfd->fd, events, osfd);
4751b5d61b8Smrg}
4761b5d61b8Smrg#endif
4771b5d61b8Smrg
4781b5d61b8Smrg#if EPOLL
4791b5d61b8Smrgstatic void
4801b5d61b8Smrgepoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
4811b5d61b8Smrg{
4821b5d61b8Smrg    struct epoll_event ev;
4831b5d61b8Smrg    ev.events = 0;
4841b5d61b8Smrg    if (osfd->xevents & X_NOTIFY_READ)
4851b5d61b8Smrg        ev.events |= EPOLLIN;
4861b5d61b8Smrg    if (osfd->xevents & X_NOTIFY_WRITE)
4871b5d61b8Smrg        ev.events |= EPOLLOUT;
4881b5d61b8Smrg    if (osfd->trigger == ospoll_trigger_edge)
4891b5d61b8Smrg        ev.events |= EPOLLET;
4901b5d61b8Smrg    ev.data.ptr = osfd;
4911b5d61b8Smrg    (void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_MOD, osfd->fd, &ev);
4921b5d61b8Smrg}
4931b5d61b8Smrg#endif
4941b5d61b8Smrg
4951b5d61b8Smrgvoid
4961b5d61b8Smrgospoll_listen(struct ospoll *ospoll, int fd, int xevents)
4971b5d61b8Smrg{
4981b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
4991b5d61b8Smrg
5001b5d61b8Smrg    if (pos >= 0) {
5011b5d61b8Smrg#if POLLSET
5021b5d61b8Smrg        struct poll_ctl ctl = { .cmd = PS_MOD, .fd = fd };
5031b5d61b8Smrg        if (xevents & X_NOTIFY_READ) {
5041b5d61b8Smrg            ctl.events |= POLLIN;
5051b5d61b8Smrg            ospoll->fds[pos].revents &= ~POLLIN;
5061b5d61b8Smrg        }
5071b5d61b8Smrg        if (xevents & X_NOTIFY_WRITE) {
5081b5d61b8Smrg            ctl.events |= POLLOUT;
5091b5d61b8Smrg            ospoll->fds[pos].revents &= ~POLLOUT;
5101b5d61b8Smrg        }
5111b5d61b8Smrg        pollset_ctl(ospoll->ps, &ctl, 1);
5121b5d61b8Smrg        ospoll->fds[pos].xevents |= xevents;
5131b5d61b8Smrg#endif
5141b5d61b8Smrg#if EPOLL || PORT
5151b5d61b8Smrg        struct ospollfd *osfd = ospoll->fds[pos];
5161b5d61b8Smrg        osfd->xevents |= xevents;
5171b5d61b8Smrg        epoll_mod(ospoll, osfd);
5181b5d61b8Smrg#endif
5191b5d61b8Smrg#if POLL
5201b5d61b8Smrg        if (xevents & X_NOTIFY_READ) {
5211b5d61b8Smrg            ospoll->fds[pos].events |= POLLIN;
5221b5d61b8Smrg            ospoll->osfds[pos].revents &= ~POLLIN;
5231b5d61b8Smrg        }
5241b5d61b8Smrg        if (xevents & X_NOTIFY_WRITE) {
5251b5d61b8Smrg            ospoll->fds[pos].events |= POLLOUT;
5261b5d61b8Smrg            ospoll->osfds[pos].revents &= ~POLLOUT;
5271b5d61b8Smrg        }
5281b5d61b8Smrg#endif
5291b5d61b8Smrg    }
5301b5d61b8Smrg}
5311b5d61b8Smrg
5321b5d61b8Smrgvoid
5331b5d61b8Smrgospoll_mute(struct ospoll *ospoll, int fd, int xevents)
5341b5d61b8Smrg{
5351b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
5361b5d61b8Smrg
5371b5d61b8Smrg    if (pos >= 0) {
5381b5d61b8Smrg#if POLLSET
5391b5d61b8Smrg        struct ospollfd *osfd = &ospoll->fds[pos];
5401b5d61b8Smrg        osfd->xevents &= ~xevents;
5411b5d61b8Smrg        struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
5421b5d61b8Smrg        pollset_ctl(ospoll->ps, &ctl, 1);
5431b5d61b8Smrg        if (osfd->xevents) {
5441b5d61b8Smrg            ctl.cmd = PS_ADD;
5451b5d61b8Smrg            if (osfd->xevents & X_NOTIFY_READ) {
5461b5d61b8Smrg                ctl.events |= POLLIN;
5471b5d61b8Smrg            }
5481b5d61b8Smrg            if (osfd->xevents & X_NOTIFY_WRITE) {
5491b5d61b8Smrg                ctl.events |= POLLOUT;
5501b5d61b8Smrg            }
5511b5d61b8Smrg            pollset_ctl(ospoll->ps, &ctl, 1);
5521b5d61b8Smrg        }
5531b5d61b8Smrg#endif
5541b5d61b8Smrg#if EPOLL || PORT
5551b5d61b8Smrg        struct ospollfd *osfd = ospoll->fds[pos];
5561b5d61b8Smrg        osfd->xevents &= ~xevents;
5571b5d61b8Smrg        epoll_mod(ospoll, osfd);
5581b5d61b8Smrg#endif
5591b5d61b8Smrg#if POLL
5601b5d61b8Smrg        if (xevents & X_NOTIFY_READ)
5611b5d61b8Smrg            ospoll->fds[pos].events &= ~POLLIN;
5621b5d61b8Smrg        if (xevents & X_NOTIFY_WRITE)
5631b5d61b8Smrg            ospoll->fds[pos].events &= ~POLLOUT;
5641b5d61b8Smrg#endif
5651b5d61b8Smrg    }
5661b5d61b8Smrg}
5671b5d61b8Smrg
5681b5d61b8Smrg
5691b5d61b8Smrgint
5701b5d61b8Smrgospoll_wait(struct ospoll *ospoll, int timeout)
5711b5d61b8Smrg{
5721b5d61b8Smrg    int nready;
5731b5d61b8Smrg#if POLLSET
5741b5d61b8Smrg#define MAX_EVENTS      256
5751b5d61b8Smrg    struct pollfd events[MAX_EVENTS];
5761b5d61b8Smrg
5771b5d61b8Smrg    nready = pollset_poll(ospoll->ps, events, MAX_EVENTS, timeout);
5781b5d61b8Smrg    for (int i = 0; i < nready; i++) {
5791b5d61b8Smrg        struct pollfd *ev = &events[i];
5801b5d61b8Smrg        int pos = ospoll_find(ospoll, ev->fd);
5811b5d61b8Smrg        struct ospollfd *osfd = &ospoll->fds[pos];
5821b5d61b8Smrg        short revents = ev->revents;
5831b5d61b8Smrg        short oldevents = osfd->revents;
5841b5d61b8Smrg
5851b5d61b8Smrg        osfd->revents = (revents & (POLLIN|POLLOUT));
5861b5d61b8Smrg        if (osfd->trigger == ospoll_trigger_edge)
5871b5d61b8Smrg            revents &= ~oldevents;
5881b5d61b8Smrg        if (revents) {
5891b5d61b8Smrg            int xevents = 0;
5901b5d61b8Smrg            if (revents & POLLIN)
5911b5d61b8Smrg                xevents |= X_NOTIFY_READ;
5921b5d61b8Smrg            if (revents & POLLOUT)
5931b5d61b8Smrg                xevents |= X_NOTIFY_WRITE;
5941b5d61b8Smrg            if (revents & (~(POLLIN|POLLOUT)))
5951b5d61b8Smrg                xevents |= X_NOTIFY_ERROR;
5961b5d61b8Smrg            osfd->callback(osfd->fd, xevents, osfd->data);
5971b5d61b8Smrg        }
5981b5d61b8Smrg    }
5991b5d61b8Smrg#endif
6001b5d61b8Smrg#if PORT
6011b5d61b8Smrg#define MAX_EVENTS      256
6021b5d61b8Smrg    port_event_t events[MAX_EVENTS];
6031b5d61b8Smrg    uint_t nget = 1;
6045a7dfde8Smrg    timespec_t port_timeout = {
6055a7dfde8Smrg        .tv_sec = timeout / 1000,
6065a7dfde8Smrg        .tv_nsec = (timeout % 1000) * 1000000
6075a7dfde8Smrg    };
6081b5d61b8Smrg
6091b5d61b8Smrg    nready = 0;
6105a7dfde8Smrg    if (port_getn(ospoll->epoll_fd, events, MAX_EVENTS, &nget, &port_timeout)
6115a7dfde8Smrg        == 0) {
6121b5d61b8Smrg        nready = nget;
6131b5d61b8Smrg    }
6141b5d61b8Smrg    for (int i = 0; i < nready; i++) {
6151b5d61b8Smrg        port_event_t *ev = &events[i];
6161b5d61b8Smrg        struct ospollfd *osfd = ev->portev_user;
6171b5d61b8Smrg        uint32_t revents = ev->portev_events;
6181b5d61b8Smrg        int xevents = 0;
6191b5d61b8Smrg
6205a7dfde8Smrg        if (revents & POLLIN)
6211b5d61b8Smrg            xevents |= X_NOTIFY_READ;
6225a7dfde8Smrg        if (revents & POLLOUT)
6231b5d61b8Smrg            xevents |= X_NOTIFY_WRITE;
6245a7dfde8Smrg        if (revents & (~(POLLIN|POLLOUT)))
6251b5d61b8Smrg            xevents |= X_NOTIFY_ERROR;
6261b5d61b8Smrg
6271b5d61b8Smrg        if (osfd->callback)
6281b5d61b8Smrg            osfd->callback(osfd->fd, xevents, osfd->data);
6291b5d61b8Smrg
6305a7dfde8Smrg        if (osfd->trigger == ospoll_trigger_level &&
6315a7dfde8Smrg            !xorg_list_is_empty(&osfd->deleted)) {
6321b5d61b8Smrg            epoll_mod(ospoll, osfd);
6331b5d61b8Smrg        }
6341b5d61b8Smrg    }
6351b5d61b8Smrg    ospoll_clean_deleted(ospoll);
6361b5d61b8Smrg#endif
6371b5d61b8Smrg#if EPOLL
6381b5d61b8Smrg#define MAX_EVENTS      256
6391b5d61b8Smrg    struct epoll_event events[MAX_EVENTS];
6401b5d61b8Smrg    int i;
6411b5d61b8Smrg
6421b5d61b8Smrg    nready = epoll_wait(ospoll->epoll_fd, events, MAX_EVENTS, timeout);
6431b5d61b8Smrg    for (i = 0; i < nready; i++) {
6441b5d61b8Smrg        struct epoll_event *ev = &events[i];
6451b5d61b8Smrg        struct ospollfd *osfd = ev->data.ptr;
6461b5d61b8Smrg        uint32_t revents = ev->events;
6471b5d61b8Smrg        int xevents = 0;
6481b5d61b8Smrg
6491b5d61b8Smrg        if (revents & EPOLLIN)
6501b5d61b8Smrg            xevents |= X_NOTIFY_READ;
6511b5d61b8Smrg        if (revents & EPOLLOUT)
6521b5d61b8Smrg            xevents |= X_NOTIFY_WRITE;
6531b5d61b8Smrg        if (revents & (~(EPOLLIN|EPOLLOUT)))
6541b5d61b8Smrg            xevents |= X_NOTIFY_ERROR;
6551b5d61b8Smrg
6561b5d61b8Smrg        if (osfd->callback)
6571b5d61b8Smrg            osfd->callback(osfd->fd, xevents, osfd->data);
6581b5d61b8Smrg    }
6591b5d61b8Smrg    ospoll_clean_deleted(ospoll);
6601b5d61b8Smrg#endif
6611b5d61b8Smrg#if POLL
6621b5d61b8Smrg    nready = xserver_poll(ospoll->fds, ospoll->num, timeout);
6631b5d61b8Smrg    ospoll->changed = FALSE;
6641b5d61b8Smrg    if (nready > 0) {
6651b5d61b8Smrg        int f;
6661b5d61b8Smrg        for (f = 0; f < ospoll->num; f++) {
6671b5d61b8Smrg            short revents = ospoll->fds[f].revents;
6681b5d61b8Smrg            short oldevents = ospoll->osfds[f].revents;
6691b5d61b8Smrg
6701b5d61b8Smrg            ospoll->osfds[f].revents = (revents & (POLLIN|POLLOUT));
6711b5d61b8Smrg            if (ospoll->osfds[f].trigger == ospoll_trigger_edge)
6721b5d61b8Smrg                revents &= ~oldevents;
6731b5d61b8Smrg            if (revents) {
6741b5d61b8Smrg                int    xevents = 0;
6751b5d61b8Smrg                if (revents & POLLIN)
6761b5d61b8Smrg                    xevents |= X_NOTIFY_READ;
6771b5d61b8Smrg                if (revents & POLLOUT)
6781b5d61b8Smrg                    xevents |= X_NOTIFY_WRITE;
6791b5d61b8Smrg                if (revents & (~(POLLIN|POLLOUT)))
6801b5d61b8Smrg                    xevents |= X_NOTIFY_ERROR;
6811b5d61b8Smrg                ospoll->osfds[f].callback(ospoll->fds[f].fd, xevents,
6821b5d61b8Smrg                                          ospoll->osfds[f].data);
6831b5d61b8Smrg
6841b5d61b8Smrg                /* Check to see if the arrays have changed, and just go back
6851b5d61b8Smrg                 * around again
6861b5d61b8Smrg                 */
6871b5d61b8Smrg                if (ospoll->changed)
6881b5d61b8Smrg                    break;
6891b5d61b8Smrg            }
6901b5d61b8Smrg        }
6911b5d61b8Smrg    }
6921b5d61b8Smrg#endif
6931b5d61b8Smrg    return nready;
6941b5d61b8Smrg}
6951b5d61b8Smrg
6961b5d61b8Smrgvoid
6971b5d61b8Smrgospoll_reset_events(struct ospoll *ospoll, int fd)
6981b5d61b8Smrg{
6991b5d61b8Smrg#if POLLSET
7001b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
7011b5d61b8Smrg
7021b5d61b8Smrg    if (pos < 0)
7031b5d61b8Smrg        return;
7041b5d61b8Smrg
7051b5d61b8Smrg    ospoll->fds[pos].revents = 0;
7061b5d61b8Smrg#endif
7071b5d61b8Smrg#if PORT
7081b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
7091b5d61b8Smrg
7101b5d61b8Smrg    if (pos < 0)
7111b5d61b8Smrg        return;
7121b5d61b8Smrg
7131b5d61b8Smrg    epoll_mod(ospoll, ospoll->fds[pos]);
7141b5d61b8Smrg#endif
7151b5d61b8Smrg#if POLL
7161b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
7171b5d61b8Smrg
7181b5d61b8Smrg    if (pos < 0)
7191b5d61b8Smrg        return;
7201b5d61b8Smrg
7211b5d61b8Smrg    ospoll->osfds[pos].revents = 0;
7221b5d61b8Smrg#endif
7231b5d61b8Smrg}
7241b5d61b8Smrg
7251b5d61b8Smrgvoid *
7261b5d61b8Smrgospoll_data(struct ospoll *ospoll, int fd)
7271b5d61b8Smrg{
7281b5d61b8Smrg    int pos = ospoll_find(ospoll, fd);
7291b5d61b8Smrg
7301b5d61b8Smrg    if (pos < 0)
7311b5d61b8Smrg        return NULL;
7321b5d61b8Smrg#if POLLSET
7331b5d61b8Smrg    return ospoll->fds[pos].data;
7341b5d61b8Smrg#endif
7351b5d61b8Smrg#if EPOLL || PORT
7361b5d61b8Smrg    return ospoll->fds[pos]->data;
7371b5d61b8Smrg#endif
7381b5d61b8Smrg#if POLL
7391b5d61b8Smrg    return ospoll->osfds[pos].data;
7401b5d61b8Smrg#endif
7411b5d61b8Smrg}
742