4 * Copyright (C) 2017-2018 Kim Alvefur
6 * This project is MIT licensed. Please see the
7 * COPYING file in the source package for more information.
20 #include <sys/epoll.h>
25 #include <sys/select.h>
32 #define STATE_MT "util.poll<epoll>"
34 #define STATE_MT "util.poll<select>"
37 #if (LUA_VERSION_NUM == 501)
38 #define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2)
42 * Structure to keep state for each type of API
44 typedef struct Lpoll_state
{
48 struct epoll_event events
[MAX_EVENTS
];
60 * Add an FD to be watched
62 static int Ladd(lua_State
*L
) {
63 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
64 int fd
= luaL_checkinteger(L
, 2);
66 int wantread
= lua_toboolean(L
, 3);
67 int wantwrite
= lua_toboolean(L
, 4);
71 lua_pushstring(L
, strerror(EBADF
));
72 lua_pushinteger(L
, EBADF
);
77 struct epoll_event event
;
79 event
.events
= (wantread
? EPOLLIN
: 0) | (wantwrite
? EPOLLOUT
: 0);
81 event
.events
|= EPOLLERR
| EPOLLHUP
| EPOLLRDHUP
;
83 int ret
= epoll_ctl(state
->epoll_fd
, EPOLL_CTL_ADD
, fd
, &event
);
88 lua_pushstring(L
, strerror(ret
));
89 lua_pushinteger(L
, ret
);
93 lua_pushboolean(L
, 1);
100 lua_pushstring(L
, strerror(EBADF
));
101 lua_pushinteger(L
, EBADF
);
105 if(FD_ISSET(fd
, &state
->all
)) {
107 lua_pushstring(L
, strerror(EEXIST
));
108 lua_pushinteger(L
, EEXIST
);
112 FD_CLR(fd
, &state
->readable
);
113 FD_CLR(fd
, &state
->writable
);
114 FD_CLR(fd
, &state
->err
);
116 FD_SET(fd
, &state
->all
);
119 FD_SET(fd
, &state
->wantread
);
122 FD_CLR(fd
, &state
->wantread
);
126 FD_SET(fd
, &state
->wantwrite
);
129 FD_CLR(fd
, &state
->wantwrite
);
132 lua_pushboolean(L
, 1);
138 * Set events to watch for, readable and/or writable
140 static int Lset(lua_State
*L
) {
141 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
142 int fd
= luaL_checkinteger(L
, 2);
146 int wantread
= lua_toboolean(L
, 3);
147 int wantwrite
= lua_toboolean(L
, 4);
149 struct epoll_event event
;
151 event
.events
= (wantread
? EPOLLIN
: 0) | (wantwrite
? EPOLLOUT
: 0);
153 event
.events
|= EPOLLERR
| EPOLLHUP
| EPOLLRDHUP
;
155 int ret
= epoll_ctl(state
->epoll_fd
, EPOLL_CTL_MOD
, fd
, &event
);
158 lua_pushboolean(L
, 1);
164 lua_pushstring(L
, strerror(ret
));
165 lua_pushinteger(L
, ret
);
171 if(!FD_ISSET(fd
, &state
->all
)) {
173 lua_pushstring(L
, strerror(ENOENT
));
174 lua_pushinteger(L
, ENOENT
);
178 if(!lua_isnoneornil(L
, 3)) {
179 if(lua_toboolean(L
, 3)) {
180 FD_SET(fd
, &state
->wantread
);
183 FD_CLR(fd
, &state
->wantread
);
187 if(!lua_isnoneornil(L
, 4)) {
188 if(lua_toboolean(L
, 4)) {
189 FD_SET(fd
, &state
->wantwrite
);
192 FD_CLR(fd
, &state
->wantwrite
);
196 lua_pushboolean(L
, 1);
204 static int Ldel(lua_State
*L
) {
205 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
206 int fd
= luaL_checkinteger(L
, 2);
210 struct epoll_event event
;
213 int ret
= epoll_ctl(state
->epoll_fd
, EPOLL_CTL_DEL
, fd
, &event
);
216 lua_pushboolean(L
, 1);
222 lua_pushstring(L
, strerror(ret
));
223 lua_pushinteger(L
, ret
);
229 if(!FD_ISSET(fd
, &state
->all
)) {
231 lua_pushstring(L
, strerror(ENOENT
));
232 lua_pushinteger(L
, ENOENT
);
236 FD_CLR(fd
, &state
->wantread
);
237 FD_CLR(fd
, &state
->wantwrite
);
238 FD_CLR(fd
, &state
->readable
);
239 FD_CLR(fd
, &state
->writable
);
240 FD_CLR(fd
, &state
->all
);
241 FD_CLR(fd
, &state
->err
);
243 lua_pushboolean(L
, 1);
250 * Check previously manipulated event state for FDs ready for reading or writing
252 static int Lpushevent(lua_State
*L
, struct Lpoll_state
*state
) {
255 if(state
->processed
> 0) {
257 struct epoll_event event
= state
->events
[state
->processed
];
258 lua_pushinteger(L
, event
.data
.fd
);
259 lua_pushboolean(L
, event
.events
& (EPOLLIN
| EPOLLHUP
| EPOLLRDHUP
| EPOLLERR
));
260 lua_pushboolean(L
, event
.events
& EPOLLOUT
);
266 for(int fd
= state
->processed
+ 1; fd
< FD_SETSIZE
; fd
++) {
267 if(FD_ISSET(fd
, &state
->readable
) || FD_ISSET(fd
, &state
->writable
) || FD_ISSET(fd
, &state
->err
)) {
268 lua_pushinteger(L
, fd
);
269 lua_pushboolean(L
, FD_ISSET(fd
, &state
->readable
) | FD_ISSET(fd
, &state
->err
));
270 lua_pushboolean(L
, FD_ISSET(fd
, &state
->writable
));
271 FD_CLR(fd
, &state
->readable
);
272 FD_CLR(fd
, &state
->writable
);
273 FD_CLR(fd
, &state
->err
);
274 state
->processed
= fd
;
286 static int Lwait(lua_State
*L
) {
287 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
289 int ret
= Lpushevent(L
, state
);
295 lua_Number timeout
= luaL_checknumber(L
, 2);
296 luaL_argcheck(L
, timeout
>= 0, 1, "positive number expected");
299 ret
= epoll_wait(state
->epoll_fd
, state
->events
, MAX_EVENTS
, timeout
* 1000);
302 * select(2) mutates the fd_sets passed to it so in order to not
303 * have to recreate it manually every time a copy is made.
305 memcpy(&state
->readable
, &state
->wantread
, sizeof(fd_set
));
306 memcpy(&state
->writable
, &state
->wantwrite
, sizeof(fd_set
));
307 memcpy(&state
->err
, &state
->all
, sizeof(fd_set
));
310 tv
.tv_sec
= (time_t)timeout
;
311 tv
.tv_usec
= ((suseconds_t
)(timeout
* 1000000)) % 1000000;
313 ret
= select(FD_SETSIZE
, &state
->readable
, &state
->writable
, &state
->err
, &tv
);
318 lua_pushstring(L
, "timeout");
321 else if(ret
< 0 && errno
== EINTR
) {
323 lua_pushstring(L
, "signal");
329 lua_pushstring(L
, strerror(ret
));
330 lua_pushinteger(L
, ret
);
335 * Search for the first ready FD and return it
338 state
->processed
= ret
;
340 state
->processed
= -1;
342 return Lpushevent(L
, state
);
349 static int Lgetfd(lua_State
*L
) {
350 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
351 lua_pushinteger(L
, state
->epoll_fd
);
358 static int Lgc(lua_State
*L
) {
359 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
361 if(state
->epoll_fd
== -1) {
365 if(close(state
->epoll_fd
) == 0) {
366 state
->epoll_fd
= -1;
369 lua_pushstring(L
, strerror(errno
));
378 * String representation
380 static int Ltos(lua_State
*L
) {
381 struct Lpoll_state
*state
= luaL_checkudata(L
, 1, STATE_MT
);
382 lua_pushfstring(L
, "%s: %p", STATE_MT
, state
);
387 * Create a new context
389 static int Lnew(lua_State
*L
) {
391 Lpoll_state
*state
= lua_newuserdata(L
, sizeof(Lpoll_state
));
392 luaL_setmetatable(L
, STATE_MT
);
394 /* Initialize state */
396 state
->epoll_fd
= -1;
397 state
->processed
= 0;
399 int epoll_fd
= epoll_create1(EPOLL_CLOEXEC
);
403 lua_pushstring(L
, strerror(errno
));
404 lua_pushinteger(L
, errno
);
408 state
->epoll_fd
= epoll_fd
;
410 FD_ZERO(&state
->wantread
);
411 FD_ZERO(&state
->wantwrite
);
412 FD_ZERO(&state
->readable
);
413 FD_ZERO(&state
->writable
);
414 FD_ZERO(&state
->all
);
415 FD_ZERO(&state
->err
);
416 state
->processed
= FD_SETSIZE
;
425 int luaopen_util_poll(lua_State
*L
) {
426 #if (LUA_VERSION_NUM > 501)
427 luaL_checkversion(L
);
430 luaL_newmetatable(L
, STATE_MT
);
433 lua_pushliteral(L
, STATE_MT
);
434 lua_setfield(L
, -2, "__name");
436 lua_pushcfunction(L
, Ltos
);
437 lua_setfield(L
, -2, "__tostring");
439 lua_createtable(L
, 0, 2);
441 lua_pushcfunction(L
, Ladd
);
442 lua_setfield(L
, -2, "add");
443 lua_pushcfunction(L
, Lset
);
444 lua_setfield(L
, -2, "set");
445 lua_pushcfunction(L
, Ldel
);
446 lua_setfield(L
, -2, "del");
447 lua_pushcfunction(L
, Lwait
);
448 lua_setfield(L
, -2, "wait");
450 lua_pushcfunction(L
, Lgetfd
);
451 lua_setfield(L
, -2, "getfd");
454 lua_setfield(L
, -2, "__index");
457 lua_pushcfunction(L
, Lgc
);
458 lua_setfield(L
, -2, "__gc");
462 lua_createtable(L
, 0, 3);
464 lua_pushcfunction(L
, Lnew
);
465 lua_setfield(L
, -2, "new");
467 #define push_errno(named_error) lua_pushinteger(L, named_error);\
468 lua_setfield(L, -2, #named_error);