Software /
code /
prosody
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 |