# HG changeset patch # User Kim Alvefur # Date 1645644663 -3600 # Node ID 6bb2f660f689e68543d3a9ce18f266b99eb1eef5 # Parent cf2086a1bd45db96dd08655b76f2ca87952c077d util.poll: Add support for the poll() API Might be better than select(), more portable than epoll. diff -r cf2086a1bd45 -r 6bb2f660f689 CHANGES --- a/CHANGES Sun Feb 27 14:36:43 2022 +0100 +++ b/CHANGES Wed Feb 23 20:31:03 2022 +0100 @@ -56,6 +56,7 @@ - MUC: support for XEP-0421 occupant identifiers - `prosodyctl check connectivity` via observe.jabber.network - libunbound for DNS queries +- The POSIX poll() API used by server_epoll on \*nix other than Linux ## Changes diff -r cf2086a1bd45 -r 6bb2f660f689 teal-src/util/poll.d.tl --- a/teal-src/util/poll.d.tl Sun Feb 27 14:36:43 2022 +0100 +++ b/teal-src/util/poll.d.tl Wed Feb 23 20:31:03 2022 +0100 @@ -17,10 +17,12 @@ local record lib new : function () : state + EEXIST : integer + EMFILE : integer ENOENT : integer - EEXIST : integer enum api_backend "epoll" + "poll" "select" end api : api_backend diff -r cf2086a1bd45 -r 6bb2f660f689 util-src/poll.c --- a/util-src/poll.c Sun Feb 27 14:36:43 2022 +0100 +++ b/util-src/poll.c Wed Feb 23 20:31:03 2022 +0100 @@ -1,7 +1,7 @@ /* * Lua polling library - * Copyright (C) 2017-2018 Kim Alvefur + * Copyright (C) 2017-2022 Kim Alvefur * * This project is MIT licensed. Please see the * COPYING file in the source package for more information. @@ -15,6 +15,9 @@ #if defined(__linux__) #define USE_EPOLL #define POLL_BACKEND "epoll" +#elif defined(__unix__) +#define USE_POLL +#define POLL_BACKEND "poll" #else #define USE_SELECT #define POLL_BACKEND "select" @@ -26,6 +29,12 @@ #define MAX_EVENTS 64 #endif #endif +#ifdef USE_POLL +#include +#ifndef MAX_EVENTS +#define MAX_EVENTS 10000 +#endif +#endif #ifdef USE_SELECT #include #endif @@ -51,6 +60,10 @@ int epoll_fd; struct epoll_event events[MAX_EVENTS]; #endif +#ifdef USE_POLL + nfds_t count; + struct pollfd events[MAX_EVENTS]; +#endif #ifdef USE_SELECT fd_set wantread; fd_set wantwrite; @@ -99,6 +112,32 @@ return 1; #endif +#ifdef USE_POLL + + for(nfds_t i = 0; i < state->count; i++) { + if(state->events[i].fd == fd) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EEXIST)); + lua_pushinteger(L, EEXIST); + return 3; + } + } + + if(state->count >= MAX_EVENTS) { + luaL_pushfail(L); + lua_pushstring(L, strerror(EMFILE)); + lua_pushinteger(L, EMFILE); + return 3; + } + + state->events[state->count].fd = fd; + state->events[state->count].events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + state->events[state->count].revents = 0; + state->count++; + + lua_pushboolean(L, 1); + return 1; +#endif #ifdef USE_SELECT if(fd > FD_SETSIZE) { @@ -173,6 +212,27 @@ } #endif +#ifdef USE_POLL + int wantread = lua_toboolean(L, 3); + int wantwrite = lua_toboolean(L, 4); + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0); + lua_pushboolean(L, 1); + return 1; + } else if(event->fd == -1) { + break; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif #ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { @@ -232,6 +292,40 @@ } #endif +#ifdef USE_POLL + + if(state->count == 0) { + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; + } + + /* + * Move the last item on top of the removed one + */ + struct pollfd *last = &state->events[state->count - 1]; + + for(nfds_t i = 0; i < state->count; i++) { + struct pollfd *event = &state->events[i]; + + if(event->fd == fd) { + event->fd = last->fd; + event->events = last->events; + event->revents = last->revents; + last->fd = -1; + state->count--; + + lua_pushboolean(L, 1); + return 1; + } + } + + luaL_pushfail(L); + lua_pushstring(L, strerror(ENOENT)); + lua_pushinteger(L, ENOENT); + return 3; +#endif #ifdef USE_SELECT if(!FD_ISSET(fd, &state->all)) { @@ -270,6 +364,22 @@ } #endif +#ifdef USE_POLL + + for(int i = state->processed - 1; i >= 0; i--) { + struct pollfd *event = &state->events[i]; + + if(event->fd != -1 && event->revents != 0) { + lua_pushinteger(L, event->fd); + lua_pushboolean(L, event->revents & (POLLIN | POLLHUP | POLLERR)); + lua_pushboolean(L, event->revents & POLLOUT); + event->revents = 0; + state->processed = i; + return 3; + } + } + +#endif #ifdef USE_SELECT for(int fd = state->processed + 1; fd < FD_SETSIZE; fd++) { @@ -307,6 +417,9 @@ #ifdef USE_EPOLL ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000); #endif +#ifdef USE_POLL + ret = poll(state->events, state->count, timeout * 1000); +#endif #ifdef USE_SELECT /* * select(2) mutates the fd_sets passed to it so in order to not @@ -349,6 +462,9 @@ #ifdef USE_EPOLL state->processed = ret; #endif +#ifdef USE_POLL + state->processed = state->count; +#endif #ifdef USE_SELECT state->processed = -1; #endif @@ -420,6 +536,17 @@ state->epoll_fd = epoll_fd; #endif +#ifdef USE_POLL + state->processed = -1; + state->count = 0; + + for(nfds_t i = 0; i < MAX_EVENTS; i++) { + state->events[i].fd = -1; + state->events[i].events = 0; + state->events[i].revents = 0; + } + +#endif #ifdef USE_SELECT FD_ZERO(&state->wantread); FD_ZERO(&state->wantwrite); @@ -482,6 +609,7 @@ lua_setfield(L, -2, #named_error); push_errno(EEXIST); + push_errno(EMFILE); push_errno(ENOENT); lua_pushliteral(L, POLL_BACKEND);