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