Comparison

util-src/poll.c @ 12316:6bb2f660f689

util.poll: Add support for the poll() API Might be better than select(), more portable than epoll.
author Kim Alvefur <zash@zash.se>
date Wed, 23 Feb 2022 20:31:03 +0100
parent 12315:cf2086a1bd45
child 12575:1f6f05a98fcd
comparison
equal deleted inserted replaced
12315:cf2086a1bd45 12316:6bb2f660f689
1 1
2 /* 2 /*
3 * Lua polling library 3 * Lua polling library
4 * Copyright (C) 2017-2018 Kim Alvefur 4 * Copyright (C) 2017-2022 Kim Alvefur
5 * 5 *
6 * This project is MIT licensed. Please see the 6 * This project is MIT licensed. Please see the
7 * COPYING file in the source package for more information. 7 * COPYING file in the source package for more information.
8 * 8 *
9 */ 9 */
13 #include <errno.h> 13 #include <errno.h>
14 14
15 #if defined(__linux__) 15 #if defined(__linux__)
16 #define USE_EPOLL 16 #define USE_EPOLL
17 #define POLL_BACKEND "epoll" 17 #define POLL_BACKEND "epoll"
18 #elif defined(__unix__)
19 #define USE_POLL
20 #define POLL_BACKEND "poll"
18 #else 21 #else
19 #define USE_SELECT 22 #define USE_SELECT
20 #define POLL_BACKEND "select" 23 #define POLL_BACKEND "select"
21 #endif 24 #endif
22 25
24 #include <sys/epoll.h> 27 #include <sys/epoll.h>
25 #ifndef MAX_EVENTS 28 #ifndef MAX_EVENTS
26 #define MAX_EVENTS 64 29 #define MAX_EVENTS 64
27 #endif 30 #endif
28 #endif 31 #endif
32 #ifdef USE_POLL
33 #include <poll.h>
34 #ifndef MAX_EVENTS
35 #define MAX_EVENTS 10000
36 #endif
37 #endif
29 #ifdef USE_SELECT 38 #ifdef USE_SELECT
30 #include <sys/select.h> 39 #include <sys/select.h>
31 #endif 40 #endif
32 41
33 #include <lualib.h> 42 #include <lualib.h>
48 typedef struct Lpoll_state { 57 typedef struct Lpoll_state {
49 int processed; 58 int processed;
50 #ifdef USE_EPOLL 59 #ifdef USE_EPOLL
51 int epoll_fd; 60 int epoll_fd;
52 struct epoll_event events[MAX_EVENTS]; 61 struct epoll_event events[MAX_EVENTS];
62 #endif
63 #ifdef USE_POLL
64 nfds_t count;
65 struct pollfd events[MAX_EVENTS];
53 #endif 66 #endif
54 #ifdef USE_SELECT 67 #ifdef USE_SELECT
55 fd_set wantread; 68 fd_set wantread;
56 fd_set wantwrite; 69 fd_set wantwrite;
57 fd_set readable; 70 fd_set readable;
97 110
98 lua_pushboolean(L, 1); 111 lua_pushboolean(L, 1);
99 return 1; 112 return 1;
100 113
101 #endif 114 #endif
115 #ifdef USE_POLL
116
117 for(nfds_t i = 0; i < state->count; i++) {
118 if(state->events[i].fd == fd) {
119 luaL_pushfail(L);
120 lua_pushstring(L, strerror(EEXIST));
121 lua_pushinteger(L, EEXIST);
122 return 3;
123 }
124 }
125
126 if(state->count >= MAX_EVENTS) {
127 luaL_pushfail(L);
128 lua_pushstring(L, strerror(EMFILE));
129 lua_pushinteger(L, EMFILE);
130 return 3;
131 }
132
133 state->events[state->count].fd = fd;
134 state->events[state->count].events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0);
135 state->events[state->count].revents = 0;
136 state->count++;
137
138 lua_pushboolean(L, 1);
139 return 1;
140 #endif
102 #ifdef USE_SELECT 141 #ifdef USE_SELECT
103 142
104 if(fd > FD_SETSIZE) { 143 if(fd > FD_SETSIZE) {
105 luaL_pushfail(L); 144 luaL_pushfail(L);
106 lua_pushstring(L, strerror(EBADF)); 145 lua_pushstring(L, strerror(EBADF));
171 lua_pushinteger(L, ret); 210 lua_pushinteger(L, ret);
172 return 3; 211 return 3;
173 } 212 }
174 213
175 #endif 214 #endif
215 #ifdef USE_POLL
216 int wantread = lua_toboolean(L, 3);
217 int wantwrite = lua_toboolean(L, 4);
218
219 for(nfds_t i = 0; i < state->count; i++) {
220 struct pollfd *event = &state->events[i];
221
222 if(event->fd == fd) {
223 event->events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0);
224 lua_pushboolean(L, 1);
225 return 1;
226 } else if(event->fd == -1) {
227 break;
228 }
229 }
230
231 luaL_pushfail(L);
232 lua_pushstring(L, strerror(ENOENT));
233 lua_pushinteger(L, ENOENT);
234 return 3;
235 #endif
176 #ifdef USE_SELECT 236 #ifdef USE_SELECT
177 237
178 if(!FD_ISSET(fd, &state->all)) { 238 if(!FD_ISSET(fd, &state->all)) {
179 luaL_pushfail(L); 239 luaL_pushfail(L);
180 lua_pushstring(L, strerror(ENOENT)); 240 lua_pushstring(L, strerror(ENOENT));
229 lua_pushstring(L, strerror(ret)); 289 lua_pushstring(L, strerror(ret));
230 lua_pushinteger(L, ret); 290 lua_pushinteger(L, ret);
231 return 3; 291 return 3;
232 } 292 }
233 293
294 #endif
295 #ifdef USE_POLL
296
297 if(state->count == 0) {
298 luaL_pushfail(L);
299 lua_pushstring(L, strerror(ENOENT));
300 lua_pushinteger(L, ENOENT);
301 return 3;
302 }
303
304 /*
305 * Move the last item on top of the removed one
306 */
307 struct pollfd *last = &state->events[state->count - 1];
308
309 for(nfds_t i = 0; i < state->count; i++) {
310 struct pollfd *event = &state->events[i];
311
312 if(event->fd == fd) {
313 event->fd = last->fd;
314 event->events = last->events;
315 event->revents = last->revents;
316 last->fd = -1;
317 state->count--;
318
319 lua_pushboolean(L, 1);
320 return 1;
321 }
322 }
323
324 luaL_pushfail(L);
325 lua_pushstring(L, strerror(ENOENT));
326 lua_pushinteger(L, ENOENT);
327 return 3;
234 #endif 328 #endif
235 #ifdef USE_SELECT 329 #ifdef USE_SELECT
236 330
237 if(!FD_ISSET(fd, &state->all)) { 331 if(!FD_ISSET(fd, &state->all)) {
238 luaL_pushfail(L); 332 luaL_pushfail(L);
265 struct epoll_event event = state->events[state->processed]; 359 struct epoll_event event = state->events[state->processed];
266 lua_pushinteger(L, event.data.fd); 360 lua_pushinteger(L, event.data.fd);
267 lua_pushboolean(L, event.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR)); 361 lua_pushboolean(L, event.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR));
268 lua_pushboolean(L, event.events & EPOLLOUT); 362 lua_pushboolean(L, event.events & EPOLLOUT);
269 return 3; 363 return 3;
364 }
365
366 #endif
367 #ifdef USE_POLL
368
369 for(int i = state->processed - 1; i >= 0; i--) {
370 struct pollfd *event = &state->events[i];
371
372 if(event->fd != -1 && event->revents != 0) {
373 lua_pushinteger(L, event->fd);
374 lua_pushboolean(L, event->revents & (POLLIN | POLLHUP | POLLERR));
375 lua_pushboolean(L, event->revents & POLLOUT);
376 event->revents = 0;
377 state->processed = i;
378 return 3;
379 }
270 } 380 }
271 381
272 #endif 382 #endif
273 #ifdef USE_SELECT 383 #ifdef USE_SELECT
274 384
305 luaL_argcheck(L, timeout >= 0, 1, "positive number expected"); 415 luaL_argcheck(L, timeout >= 0, 1, "positive number expected");
306 416
307 #ifdef USE_EPOLL 417 #ifdef USE_EPOLL
308 ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000); 418 ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000);
309 #endif 419 #endif
420 #ifdef USE_POLL
421 ret = poll(state->events, state->count, timeout * 1000);
422 #endif
310 #ifdef USE_SELECT 423 #ifdef USE_SELECT
311 /* 424 /*
312 * select(2) mutates the fd_sets passed to it so in order to not 425 * select(2) mutates the fd_sets passed to it so in order to not
313 * have to recreate it manually every time a copy is made. 426 * have to recreate it manually every time a copy is made.
314 */ 427 */
347 * Search for the first ready FD and return it 460 * Search for the first ready FD and return it
348 */ 461 */
349 #ifdef USE_EPOLL 462 #ifdef USE_EPOLL
350 state->processed = ret; 463 state->processed = ret;
351 #endif 464 #endif
465 #ifdef USE_POLL
466 state->processed = state->count;
467 #endif
352 #ifdef USE_SELECT 468 #ifdef USE_SELECT
353 state->processed = -1; 469 state->processed = -1;
354 #endif 470 #endif
355 return Lpushevent(L, state); 471 return Lpushevent(L, state);
356 } 472 }
417 lua_pushinteger(L, errno); 533 lua_pushinteger(L, errno);
418 return 3; 534 return 3;
419 } 535 }
420 536
421 state->epoll_fd = epoll_fd; 537 state->epoll_fd = epoll_fd;
538 #endif
539 #ifdef USE_POLL
540 state->processed = -1;
541 state->count = 0;
542
543 for(nfds_t i = 0; i < MAX_EVENTS; i++) {
544 state->events[i].fd = -1;
545 state->events[i].events = 0;
546 state->events[i].revents = 0;
547 }
548
422 #endif 549 #endif
423 #ifdef USE_SELECT 550 #ifdef USE_SELECT
424 FD_ZERO(&state->wantread); 551 FD_ZERO(&state->wantread);
425 FD_ZERO(&state->wantwrite); 552 FD_ZERO(&state->wantwrite);
426 FD_ZERO(&state->readable); 553 FD_ZERO(&state->readable);
480 607
481 #define push_errno(named_error) lua_pushinteger(L, named_error);\ 608 #define push_errno(named_error) lua_pushinteger(L, named_error);\
482 lua_setfield(L, -2, #named_error); 609 lua_setfield(L, -2, #named_error);
483 610
484 push_errno(EEXIST); 611 push_errno(EEXIST);
612 push_errno(EMFILE);
485 push_errno(ENOENT); 613 push_errno(ENOENT);
486 614
487 lua_pushliteral(L, POLL_BACKEND); 615 lua_pushliteral(L, POLL_BACKEND);
488 lua_setfield(L, -2, "api"); 616 lua_setfield(L, -2, "api");
489 617