aboutsummaryrefslogtreecommitdiffstats
path: root/util-src/poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-src/poll.c')
-rw-r--r--util-src/poll.c172
1 files changed, 156 insertions, 16 deletions
diff --git a/util-src/poll.c b/util-src/poll.c
index 6c6a4e63..81caa953 100644
--- a/util-src/poll.c
+++ b/util-src/poll.c
@@ -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.
@@ -12,8 +12,15 @@
#include <string.h>
#include <errno.h>
-#ifdef __linux__
+#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"
#endif
#ifdef USE_EPOLL
@@ -21,18 +28,21 @@
#ifndef MAX_EVENTS
#define MAX_EVENTS 64
#endif
-#else
+#endif
+#ifdef USE_POLL
+#include <poll.h>
+#ifndef MAX_EVENTS
+#define MAX_EVENTS 10000
+#endif
+#endif
+#ifdef USE_SELECT
#include <sys/select.h>
#endif
#include <lualib.h>
#include <lauxlib.h>
-#ifdef USE_EPOLL
-#define STATE_MT "util.poll<epoll>"
-#else
-#define STATE_MT "util.poll<select>"
-#endif
+#define STATE_MT "util.poll<" POLL_BACKEND ">"
#if (LUA_VERSION_NUM == 501)
#define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2)
@@ -49,7 +59,12 @@ typedef struct Lpoll_state {
#ifdef USE_EPOLL
int epoll_fd;
struct epoll_event events[MAX_EVENTS];
-#else
+#endif
+#ifdef USE_POLL
+ nfds_t count;
+ struct pollfd events[MAX_EVENTS];
+#endif
+#ifdef USE_SELECT
fd_set wantread;
fd_set wantwrite;
fd_set readable;
@@ -96,7 +111,34 @@ static int Ladd(lua_State *L) {
lua_pushboolean(L, 1);
return 1;
-#else
+#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) {
luaL_pushfail(L);
@@ -169,7 +211,29 @@ static int Lset(lua_State *L) {
return 3;
}
-#else
+#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)) {
luaL_pushfail(L);
@@ -227,7 +291,42 @@ static int Ldel(lua_State *L) {
return 3;
}
-#else
+#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)) {
luaL_pushfail(L);
@@ -264,7 +363,24 @@ static int Lpushevent(lua_State *L, struct Lpoll_state *state) {
return 3;
}
-#else
+#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++) {
if(FD_ISSET(fd, &state->readable) || FD_ISSET(fd, &state->writable) || FD_ISSET(fd, &state->err)) {
@@ -300,7 +416,11 @@ static int Lwait(lua_State *L) {
#ifdef USE_EPOLL
ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000);
-#else
+#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
* have to recreate it manually every time a copy is made.
@@ -341,7 +461,11 @@ static int Lwait(lua_State *L) {
*/
#ifdef USE_EPOLL
state->processed = ret;
-#else
+#endif
+#ifdef USE_POLL
+ state->processed = state->count;
+#endif
+#ifdef USE_SELECT
state->processed = -1;
#endif
return Lpushevent(L, state);
@@ -411,7 +535,19 @@ static int Lnew(lua_State *L) {
}
state->epoll_fd = epoll_fd;
-#else
+#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);
FD_ZERO(&state->readable);
@@ -473,8 +609,12 @@ int luaopen_util_poll(lua_State *L) {
lua_setfield(L, -2, #named_error);
push_errno(EEXIST);
+ push_errno(EMFILE);
push_errno(ENOENT);
+ lua_pushliteral(L, POLL_BACKEND);
+ lua_setfield(L, -2, "api");
+
}
return 1;
}