1 #include "first.h"
2
3 #include "fdevent_impl.h"
4 #include "fdevent.h"
5 #include "buffer.h"
6 #include "log.h"
7
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #ifdef _WIN32
15 #include <winsock2.h> /* closesocket */
16 #endif
17
18 #ifdef FDEVENT_USE_LINUX_EPOLL
19 __attribute_cold__
20 static int fdevent_linux_sysepoll_init(struct fdevents *ev);
21 #endif
22 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
23 __attribute_cold__
24 static int fdevent_freebsd_kqueue_init(struct fdevents *ev);
25 #endif
26 #ifdef FDEVENT_USE_SOLARIS_PORT
27 __attribute_cold__
28 static int fdevent_solaris_port_init(struct fdevents *ev);
29 #endif
30 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
31 __attribute_cold__
32 static int fdevent_solaris_devpoll_init(struct fdevents *ev);
33 #endif
34 #ifdef FDEVENT_USE_LIBEV
35 __attribute_cold__
36 static int fdevent_libev_init(struct fdevents *ev);
37 #endif
38 #ifdef FDEVENT_USE_POLL
39 __attribute_cold__
40 static int fdevent_poll_init(struct fdevents *ev);
41 #endif
42 #ifdef FDEVENT_USE_SELECT
43 __attribute_cold__
44 static int fdevent_select_init(struct fdevents *ev);
45 #endif
46
47
48 int
fdevent_config(const char ** event_handler_name,log_error_st * errh)49 fdevent_config (const char **event_handler_name, log_error_st *errh)
50 {
51 static const struct ev_map { fdevent_handler_t et; const char *name; }
52 event_handlers[] =
53 {
54 /* - epoll is most reliable
55 * - select works everywhere
56 */
57 #ifdef FDEVENT_USE_LINUX_EPOLL
58 { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
59 { FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" },
60 #endif
61 #ifdef FDEVENT_USE_SOLARIS_PORT
62 { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
63 #endif
64 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
65 { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
66 #endif
67 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
68 { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
69 { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
70 #endif
71 #ifdef FDEVENT_USE_POLL
72 { FDEVENT_HANDLER_POLL, "poll" },
73 #endif
74 #ifdef FDEVENT_USE_SELECT
75 { FDEVENT_HANDLER_SELECT, "select" },
76 #endif
77 #ifdef FDEVENT_USE_LIBEV
78 { FDEVENT_HANDLER_LIBEV, "libev" },
79 #endif
80 { FDEVENT_HANDLER_UNSET, NULL }
81 };
82
83 const char *event_handler = *event_handler_name;
84 fdevent_handler_t et = FDEVENT_HANDLER_UNSET;
85
86 #ifndef FDEVENT_USE_LIBEV
87 if (NULL != event_handler && 0 == strcmp(event_handler, "libev"))
88 event_handler = NULL;
89 #endif
90 #ifdef FDEVENT_USE_POLL
91 if (NULL != event_handler && 0 == strcmp(event_handler, "select"))
92 event_handler = "poll";
93 #endif
94
95 if (NULL == event_handler) {
96 /* choose a good default
97 *
98 * the event_handler list is sorted by 'goodness'
99 * taking the first available should be the best solution
100 */
101 et = event_handlers[0].et;
102 *event_handler_name = event_handlers[0].name;
103
104 if (FDEVENT_HANDLER_UNSET == et) {
105 log_error(errh, __FILE__, __LINE__,
106 "sorry, there is no event handler for this system");
107
108 return -1;
109 }
110 }
111 else {
112 /*
113 * User override
114 */
115
116 for (uint32_t i = 0; event_handlers[i].name; ++i) {
117 if (0 == strcmp(event_handlers[i].name, event_handler)) {
118 et = event_handlers[i].et;
119 break;
120 }
121 }
122
123 if (FDEVENT_HANDLER_UNSET == et) {
124 log_error(errh, __FILE__, __LINE__,
125 "the selected event-handler in unknown or not supported: %s",
126 event_handler);
127 return -1;
128 }
129 }
130
131 return et;
132 }
133
134
135 const char *
fdevent_show_event_handlers(void)136 fdevent_show_event_handlers (void)
137 {
138 return
139 "\nEvent Handlers:\n\n"
140 #ifdef FDEVENT_USE_SELECT
141 "\t+ select (generic)\n"
142 #else
143 "\t- select (generic)\n"
144 #endif
145 #ifdef FDEVENT_USE_POLL
146 "\t+ poll (Unix)\n"
147 #else
148 "\t- poll (Unix)\n"
149 #endif
150 #ifdef FDEVENT_USE_LINUX_EPOLL
151 "\t+ epoll (Linux)\n"
152 #else
153 "\t- epoll (Linux)\n"
154 #endif
155 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
156 "\t+ /dev/poll (Solaris)\n"
157 #else
158 "\t- /dev/poll (Solaris)\n"
159 #endif
160 #ifdef FDEVENT_USE_SOLARIS_PORT
161 "\t+ eventports (Solaris)\n"
162 #else
163 "\t- eventports (Solaris)\n"
164 #endif
165 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
166 "\t+ kqueue (FreeBSD)\n"
167 #else
168 "\t- kqueue (FreeBSD)\n"
169 #endif
170 #ifdef FDEVENT_USE_LIBEV
171 "\t+ libev (generic)\n"
172 #else
173 "\t- libev (generic)\n"
174 #endif
175 ;
176 }
177
178
179 fdevents *
fdevent_init(const char * event_handler,int * max_fds,int * cur_fds,log_error_st * errh)180 fdevent_init (const char *event_handler, int *max_fds, int *cur_fds, log_error_st *errh)
181 {
182 fdevents *ev;
183 uint32_t maxfds = (0 != *max_fds)
184 ? (uint32_t)*max_fds
185 : 4096;
186 int type = fdevent_config(&event_handler, errh);
187 if (type <= 0) return NULL;
188
189 fdevent_socket_nb_cloexec_init();
190
191 #ifdef FDEVENT_USE_SELECT
192 /* select limits itself
193 * as it is a hard limit and will lead to a segfault we add some safety
194 * */
195 if (type == FDEVENT_HANDLER_SELECT) {
196 if (maxfds > (uint32_t)FD_SETSIZE - 200)
197 maxfds = (uint32_t)FD_SETSIZE - 200;
198 }
199 #endif
200 *max_fds = (int)maxfds;
201 ++maxfds; /*(+1 for event-handler fd)*/
202
203 ev = calloc(1, sizeof(*ev));
204 force_assert(NULL != ev);
205 ev->errh = errh;
206 ev->cur_fds = cur_fds;
207 ev->event_handler = event_handler;
208 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
209 if (NULL == ev->fdarray) {
210 log_error(ev->errh, __FILE__, __LINE__,
211 "server.max-fds too large? (%u)", maxfds-1);
212 free(ev);
213 return NULL;
214 }
215 ev->maxfds = maxfds;
216
217 switch(type) {
218 #ifdef FDEVENT_USE_POLL
219 case FDEVENT_HANDLER_POLL:
220 if (0 == fdevent_poll_init(ev)) return ev;
221 break;
222 #endif
223 #ifdef FDEVENT_USE_SELECT
224 case FDEVENT_HANDLER_SELECT:
225 if (0 == fdevent_select_init(ev)) return ev;
226 break;
227 #endif
228 #ifdef FDEVENT_USE_LINUX_EPOLL
229 case FDEVENT_HANDLER_LINUX_SYSEPOLL:
230 if (0 == fdevent_linux_sysepoll_init(ev)) return ev;
231 break;
232 #endif
233 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
234 case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
235 if (0 == fdevent_solaris_devpoll_init(ev)) return ev;
236 break;
237 #endif
238 #ifdef FDEVENT_USE_SOLARIS_PORT
239 case FDEVENT_HANDLER_SOLARIS_PORT:
240 if (0 == fdevent_solaris_port_init(ev)) return ev;
241 break;
242 #endif
243 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
244 case FDEVENT_HANDLER_FREEBSD_KQUEUE:
245 if (0 == fdevent_freebsd_kqueue_init(ev)) return ev;
246 break;
247 #endif
248 #ifdef FDEVENT_USE_LIBEV
249 case FDEVENT_HANDLER_LIBEV:
250 if (0 == fdevent_libev_init(ev)) return ev;
251 break;
252 #endif
253 /*case FDEVENT_HANDLER_UNSET:*/
254 default:
255 break;
256 }
257
258 free(ev->fdarray);
259 free(ev);
260
261 log_error(errh, __FILE__, __LINE__,
262 "event-handler failed: %s; "
263 "try to set server.event-handler = \"poll\" or \"select\"",
264 event_handler);
265 return NULL;
266 }
267
268
269 void
fdevent_free(fdevents * ev)270 fdevent_free (fdevents *ev)
271 {
272 if (!ev) return;
273 if (ev->free) ev->free(ev);
274
275 for (uint32_t i = 0; i < ev->maxfds; ++i) {
276 /* (fdevent_sched_run() should already have been run,
277 * but take reasonable precautions anyway) */
278 if (ev->fdarray[i])
279 free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3));
280 }
281
282 free(ev->fdarray);
283 free(ev);
284 }
285
286
287 int
fdevent_reset(fdevents * ev)288 fdevent_reset (fdevents *ev)
289 {
290 int rc = (NULL != ev->reset) ? ev->reset(ev) : 0;
291 if (-1 == rc) {
292 log_error(ev->errh, __FILE__, __LINE__,
293 "event-handler failed: %s; "
294 "try to set server.event-handler = \"poll\" or \"select\"",
295 ev->event_handler ? ev->event_handler : "");
296 }
297 return rc;
298 }
299
300
301 static void
fdevent_sched_run(fdevents * const ev)302 fdevent_sched_run (fdevents * const ev)
303 {
304 for (fdnode *fdn = ev->pendclose; fdn; ) {
305 int fd, rc;
306 #ifdef _WIN32
307 rc = (uintptr_t)fdn & 0x3;
308 #endif
309 fdn = (fdnode *)((uintptr_t)fdn & ~0x3);
310 fd = fdn->fd;
311 #ifdef _WIN32
312 if (rc == 0x1) {
313 rc = closesocket(fd);
314 }
315 else if (rc == 0x2) {
316 rc = close(fd);
317 }
318 #else
319 rc = close(fd);
320 #endif
321
322 if (0 != rc) {
323 log_perror(ev->errh, __FILE__, __LINE__, "close failed %d", fd);
324 }
325 else {
326 --(*ev->cur_fds);
327 }
328
329 fdnode * const fdn_tmp = fdn;
330 fdn = (fdnode *)fdn->ctx; /* next */
331 /*(fdevent_unregister)*/
332 free(fdn_tmp); /*fdnode_free(fdn_tmp);*/
333 ev->fdarray[fd] = NULL;
334 }
335 ev->pendclose = NULL;
336 }
337
338
339 int
fdevent_poll(fdevents * const ev,const int timeout_ms)340 fdevent_poll (fdevents * const ev, const int timeout_ms)
341 {
342 const int n = ev->poll(ev, ev->pendclose ? 0 : timeout_ms);
343 if (n >= 0)
344 fdevent_sched_run(ev);
345 else if (errno != EINTR)
346 log_perror(ev->errh, __FILE__, __LINE__, "fdevent_poll failed");
347 return n;
348 }
349
350
351 #ifdef FDEVENT_USE_LINUX_EPOLL
352
353 #include <sys/epoll.h>
354
355 static int
fdevent_linux_sysepoll_event_del(fdevents * ev,fdnode * fdn)356 fdevent_linux_sysepoll_event_del (fdevents *ev, fdnode *fdn)
357 {
358 return epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fdn->fd, NULL);
359 }
360
361 static int
fdevent_linux_sysepoll_event_set(fdevents * ev,fdnode * fdn,int events)362 fdevent_linux_sysepoll_event_set (fdevents *ev, fdnode *fdn, int events)
363 {
364 int op = (-1 == fdn->fde_ndx) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
365 int fd = fdn->fde_ndx = fdn->fd;
366 struct epoll_event ep;
367 #ifndef EPOLLRDHUP
368 events &= ~FDEVENT_RDHUP;
369 #endif
370 ep.events = events | EPOLLERR | EPOLLHUP;
371 ep.data.ptr = fdn;
372 return epoll_ctl(ev->epoll_fd, op, fd, &ep);
373 }
374
375 static int
fdevent_linux_sysepoll_poll(fdevents * const ev,int timeout_ms)376 fdevent_linux_sysepoll_poll (fdevents * const ev, int timeout_ms)
377 {
378 struct epoll_event * const restrict epoll_events = ev->epoll_events;
379 int n = epoll_wait(ev->epoll_fd, epoll_events, ev->maxfds, timeout_ms);
380 for (int i = 0; i < n; ++i) {
381 fdnode * const fdn = (fdnode *)epoll_events[i].data.ptr;
382 int revents = epoll_events[i].events;
383 if ((fdevent_handler)NULL != fdn->handler)
384 (*fdn->handler)(fdn->ctx, revents);
385 }
386 return n;
387 }
388
389 __attribute_cold__
390 static void
fdevent_linux_sysepoll_free(fdevents * ev)391 fdevent_linux_sysepoll_free (fdevents *ev)
392 {
393 close(ev->epoll_fd);
394 free(ev->epoll_events);
395 }
396
397 __attribute_cold__
398 static int
fdevent_linux_sysepoll_init(fdevents * ev)399 fdevent_linux_sysepoll_init (fdevents *ev)
400 {
401 force_assert(EPOLLIN == FDEVENT_IN);
402 force_assert(EPOLLPRI == FDEVENT_PRI);
403 force_assert(EPOLLOUT == FDEVENT_OUT);
404 force_assert(EPOLLERR == FDEVENT_ERR);
405 force_assert(EPOLLHUP == FDEVENT_HUP);
406 #ifdef EPOLLRDHUP
407 force_assert(EPOLLRDHUP == FDEVENT_RDHUP);
408 #endif
409
410 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
411 ev->event_set = fdevent_linux_sysepoll_event_set;
412 ev->event_del = fdevent_linux_sysepoll_event_del;
413 ev->poll = fdevent_linux_sysepoll_poll;
414 ev->free = fdevent_linux_sysepoll_free;
415
416 #ifdef EPOLL_CLOEXEC
417 if (-1 == (ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC))) return -1;
418 #else
419 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) return -1;
420 fdevent_setfd_cloexec(ev->epoll_fd);
421 #endif
422
423 ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
424 force_assert(NULL != ev->epoll_events);
425
426 return 0;
427 }
428
429 #endif /* FDEVENT_USE_LINUX_EPOLL */
430
431
432 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
433
434 #include <sys/event.h>
435 #include <sys/time.h>
436 #include <fcntl.h>
437
438 static int
fdevent_freebsd_kqueue_event_del(fdevents * ev,fdnode * fdn)439 fdevent_freebsd_kqueue_event_del (fdevents *ev, fdnode *fdn)
440 {
441 struct kevent kev[2];
442 struct timespec ts = {0, 0};
443 int fd = fdn->fd;
444 int n = 0;
445 int oevents = fdn->events;
446
447 if (oevents & FDEVENT_IN) {
448 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
449 n++;
450 }
451 if (oevents & FDEVENT_OUT) {
452 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
453 n++;
454 }
455
456 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
457 /*(kevent() changelist still processed on EINTR,
458 * but EINTR should not be received since 0 == nevents)*/
459 }
460
461 static int
fdevent_freebsd_kqueue_event_set(fdevents * ev,fdnode * fdn,int events)462 fdevent_freebsd_kqueue_event_set (fdevents *ev, fdnode *fdn, int events)
463 {
464 struct kevent kev[2];
465 struct timespec ts = {0, 0};
466 int fd = fdn->fde_ndx = fdn->fd;
467 int n = 0;
468 int oevents = fdn->events;
469 int addevents = events & ~oevents;
470 int delevents = ~events & oevents;
471
472 if (addevents & FDEVENT_IN) {
473 EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn);
474 n++;
475 }
476 else if (delevents & FDEVENT_IN) {
477 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
478 n++;
479 }
480
481 if (addevents & FDEVENT_OUT) {
482 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn);
483 n++;
484 }
485 else if (delevents & FDEVENT_OUT) {
486 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
487 n++;
488 }
489
490 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
491 /*(kevent() changelist still processed on EINTR,
492 * but EINTR should not be received since 0 == nevents)*/
493 }
494
495 static int
fdevent_freebsd_kqueue_poll(fdevents * const ev,int timeout_ms)496 fdevent_freebsd_kqueue_poll (fdevents * const ev, int timeout_ms)
497 {
498 struct timespec ts;
499 ts.tv_sec = timeout_ms / 1000;
500 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
501
502 struct kevent * const restrict kq_results = ev->kq_results;
503 const int n = kevent(ev->kq_fd, NULL, 0, kq_results, ev->maxfds, &ts);
504
505 for (int i = 0; i < n; ++i) {
506 fdnode * const fdn = (fdnode *)kq_results[i].udata;
507 int filt = kq_results[i].filter;
508 int e = kq_results[i].flags;
509 if ((fdevent_handler)NULL != fdn->handler) {
510 int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT;
511 if (e & EV_EOF)
512 revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP);
513 if (e & EV_ERROR)
514 revents |= FDEVENT_ERR;
515 (*fdn->handler)(fdn->ctx, revents);
516 }
517 }
518 return n;
519 }
520
521 __attribute_cold__
522 static int
fdevent_freebsd_kqueue_reset(fdevents * ev)523 fdevent_freebsd_kqueue_reset (fdevents *ev)
524 {
525 #ifdef __NetBSD__
526 ev->kq_fd = kqueue1(O_NONBLOCK|O_CLOEXEC|O_NOSIGPIPE);
527 return (-1 != ev->kq_fd) ? 0 : -1;
528 #else
529 ev->kq_fd = kqueue();
530 if (-1 == ev->kq_fd) return -1;
531 fdevent_setfd_cloexec(ev->kq_fd);
532 return 0;
533 #endif
534 }
535
536 __attribute_cold__
537 static void
fdevent_freebsd_kqueue_free(fdevents * ev)538 fdevent_freebsd_kqueue_free (fdevents *ev)
539 {
540 close(ev->kq_fd);
541 free(ev->kq_results);
542 }
543
544 __attribute_cold__
545 static int
fdevent_freebsd_kqueue_init(fdevents * ev)546 fdevent_freebsd_kqueue_init (fdevents *ev)
547 {
548 ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE;
549 ev->event_set = fdevent_freebsd_kqueue_event_set;
550 ev->event_del = fdevent_freebsd_kqueue_event_del;
551 ev->poll = fdevent_freebsd_kqueue_poll;
552 ev->reset = fdevent_freebsd_kqueue_reset;
553 ev->free = fdevent_freebsd_kqueue_free;
554 ev->kq_fd = -1;
555 ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
556 force_assert(NULL != ev->kq_results);
557 return 0;
558 }
559
560 #endif /* FDEVENT_USE_FREEBSD_KQUEUE */
561
562
563 #ifdef FDEVENT_USE_SOLARIS_PORT
564
565 #include <sys/poll.h>
566 #include <fcntl.h>
567
568 static int
fdevent_solaris_port_event_del(fdevents * ev,fdnode * fdn)569 fdevent_solaris_port_event_del (fdevents *ev, fdnode *fdn)
570 {
571 return port_dissociate(ev->port_fd, PORT_SOURCE_FD, fdn->fd);
572 }
573
574 static int
fdevent_solaris_port_event_set(fdevents * ev,fdnode * fdn,int events)575 fdevent_solaris_port_event_set (fdevents *ev, fdnode *fdn, int events)
576 {
577 int fd = fdn->fde_ndx = fdn->fd;
578 intptr_t ud = events & (POLLIN|POLLOUT);
579 return port_associate(ev->port_fd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud);
580 }
581
582 /* if there is any error it will return the return values of port_getn,
583 * otherwise it will return number of events */
584 static int
fdevent_solaris_port_poll(fdevents * ev,int timeout_ms)585 fdevent_solaris_port_poll (fdevents *ev, int timeout_ms)
586 {
587 const int pfd = ev->port_fd;
588 int ret;
589 unsigned int available_events, wait_for_events = 0;
590
591 struct timespec timeout;
592
593 timeout.tv_sec = timeout_ms/1000L;
594 timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L;
595
596 /* get the number of file descriptors with events */
597 if ((ret = port_getn(pfd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret;
598
599 /* wait for at least one event */
600 if (0 == wait_for_events) wait_for_events = 1;
601
602 available_events = wait_for_events;
603
604 /* get the events of the file descriptors */
605 if ((ret = port_getn(pfd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) {
606 /* if errno == ETIME and available_event == wait_for_events we didn't get any events */
607 /* for other errors we didn't get any events either */
608 if (!(errno == ETIME && wait_for_events != available_events)) return ret;
609 }
610
611 for (int i = 0; i < (int)available_events; ++i) {
612 int fd = (int)ev->port_events[i].portev_object;
613 fdnode * const fdn = ev->fdarray[fd];
614 const intptr_t ud = (intptr_t)ev->port_events[i].portev_user;
615 int revents = ev->port_events[i].portev_events;
616 if (0 == ((uintptr_t)fdn & 0x3)) {
617 if (port_associate(pfd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud) < 0)
618 log_error(ev->errh,__FILE__,__LINE__,"port_associate failed");
619 (*fdn->handler)(fdn->ctx, revents);
620 }
621 else {
622 fdn->fde_ndx = -1;
623 }
624 }
625 return available_events;
626 }
627
628 __attribute_cold__
629 static void
fdevent_solaris_port_free(fdevents * ev)630 fdevent_solaris_port_free (fdevents *ev)
631 {
632 close(ev->port_fd);
633 free(ev->port_events);
634 }
635
636 __attribute_cold__
637 static int
fdevent_solaris_port_init(fdevents * ev)638 fdevent_solaris_port_init (fdevents *ev)
639 {
640 force_assert(POLLIN == FDEVENT_IN);
641 force_assert(POLLPRI == FDEVENT_PRI);
642 force_assert(POLLOUT == FDEVENT_OUT);
643 force_assert(POLLERR == FDEVENT_ERR);
644 force_assert(POLLHUP == FDEVENT_HUP);
645 force_assert(POLLNVAL == FDEVENT_NVAL);
646 #ifdef POLLRDHUP
647 force_assert(POLLRDHUP == FDEVENT_RDHUP);
648 #endif
649
650 ev->type = FDEVENT_HANDLER_SOLARIS_PORT;
651 ev->event_set = fdevent_solaris_port_event_set;
652 ev->event_del = fdevent_solaris_port_event_del;
653 ev->poll = fdevent_solaris_port_poll;
654 ev->free = fdevent_solaris_port_free;
655 ev->port_events = malloc(ev->maxfds * sizeof(*ev->port_events));
656 force_assert(NULL != ev->port_events);
657
658 if ((ev->port_fd = port_create()) < 0) return -1;
659
660 return 0;
661 }
662
663 #endif /* FDEVENT_USE_SOLARIS_PORT */
664
665
666 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
667
668 #include <sys/devpoll.h>
669 #include <sys/ioctl.h>
670 #include <fcntl.h>
671
672 static int
fdevent_solaris_devpoll_event_del(fdevents * ev,fdnode * fdn)673 fdevent_solaris_devpoll_event_del (fdevents *ev, fdnode *fdn)
674 {
675 struct pollfd pfd;
676 pfd.fd = fdn->fd;
677 pfd.events = POLLREMOVE;
678 pfd.revents = 0;
679 return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
680 }
681
682 static int
fdevent_solaris_devpoll_event_set(fdevents * ev,fdnode * fdn,int events)683 fdevent_solaris_devpoll_event_set (fdevents *ev, fdnode *fdn, int events)
684 {
685 struct pollfd pfd;
686 pfd.fd = fdn->fde_ndx = fdn->fd;
687 #ifndef POLLRDHUP
688 events &= ~FDEVENT_RDHUP;
689 #endif
690 pfd.events = events;
691 pfd.revents = 0;
692 return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
693 }
694
695 static int
fdevent_solaris_devpoll_poll(fdevents * ev,int timeout_ms)696 fdevent_solaris_devpoll_poll (fdevents *ev, int timeout_ms)
697 {
698 fdnode ** const fdarray = ev->fdarray;
699 struct pollfd * const devpollfds = ev->devpollfds;
700 struct dvpoll dopoll;
701
702 dopoll.dp_timeout = timeout_ms;
703 dopoll.dp_nfds = ev->maxfds - 1;
704 dopoll.dp_fds = devpollfds;
705
706 const int n = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
707
708 for (int i = 0; i < n; ++i) {
709 fdnode * const fdn = fdarray[devpollfds[i].fd];
710 int revents = devpollfds[i].revents;
711 if (0 == ((uintptr_t)fdn & 0x3))
712 (*fdn->handler)(fdn->ctx, revents);
713 }
714 return n;
715 }
716
717 __attribute_cold__
718 static int
fdevent_solaris_devpoll_reset(fdevents * ev)719 fdevent_solaris_devpoll_reset (fdevents *ev)
720 {
721 /* a forked process does only inherit the filedescriptor,
722 * but every operation on the device will lead to a EACCES */
723 ev->devpoll_fd = fdevent_open_cloexec("/dev/poll", 1, O_RDWR, 0);
724 return (ev->devpoll_fd >= 0) ? 0 : -1;
725 }
726
727 __attribute_cold__
728 static void
fdevent_solaris_devpoll_free(fdevents * ev)729 fdevent_solaris_devpoll_free (fdevents *ev)
730 {
731 free(ev->devpollfds);
732 close(ev->devpoll_fd);
733 }
734
735 __attribute_cold__
736 static int
fdevent_solaris_devpoll_init(fdevents * ev)737 fdevent_solaris_devpoll_init (fdevents *ev)
738 {
739 force_assert(POLLIN == FDEVENT_IN);
740 force_assert(POLLPRI == FDEVENT_PRI);
741 force_assert(POLLOUT == FDEVENT_OUT);
742 force_assert(POLLERR == FDEVENT_ERR);
743 force_assert(POLLHUP == FDEVENT_HUP);
744 force_assert(POLLNVAL == FDEVENT_NVAL);
745 #ifdef POLLRDHUP
746 force_assert(POLLRDHUP == FDEVENT_RDHUP);
747 #endif
748
749 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
750 ev->event_set = fdevent_solaris_devpoll_event_set;
751 ev->event_del = fdevent_solaris_devpoll_event_del;
752 ev->poll = fdevent_solaris_devpoll_poll;
753 ev->reset = fdevent_solaris_devpoll_reset;
754 ev->free = fdevent_solaris_devpoll_free;
755 ev->devpoll_fd = -1;
756 ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
757 force_assert(NULL != ev->devpollfds);
758 return 0;
759 }
760
761 #endif /* FDEVENT_USE_SOLARIS_DEVPOLL */
762
763
764 #ifdef FDEVENT_USE_LIBEV
765
766 #if (defined(__APPLE__) && defined(__MACH__)) \
767 || defined(__FreeBSD__) || defined(__NetBSD__) \
768 || defined(__OpenBSD__) || defined(__DragonFly__)
769 /* libev EV_ERROR conflicts with kqueue sys/event.h EV_ERROR */
770 #undef EV_ERROR
771 #endif
772
773 #include <ev.h>
774
775 static void
fdevent_libev_io_watcher_cb(struct ev_loop * loop,ev_io * w,int revents)776 fdevent_libev_io_watcher_cb (struct ev_loop *loop, ev_io *w, int revents)
777 {
778 fdevents *ev = w->data;
779 fdnode *fdn = ev->fdarray[w->fd];
780 int rv = 0;
781 UNUSED(loop);
782
783 if (revents & EV_READ) rv |= FDEVENT_IN;
784 if (revents & EV_WRITE) rv |= FDEVENT_OUT;
785 if (revents & EV_ERROR) rv |= FDEVENT_ERR;
786
787 if (0 == ((uintptr_t)fdn & 0x3))
788 (*fdn->handler)(fdn->ctx, rv);
789 }
790
791 static int
fdevent_libev_event_del(fdevents * ev,fdnode * fdn)792 fdevent_libev_event_del (fdevents *ev, fdnode *fdn)
793 {
794 ev_io *watcher = fdn->handler_ctx;
795 if (!watcher) return 0;
796 fdn->handler_ctx = NULL;
797
798 ev_io_stop(ev->libev_loop, watcher);
799 free(watcher);
800
801 return 0;
802 }
803
804 static int
fdevent_libev_event_set(fdevents * ev,fdnode * fdn,int events)805 fdevent_libev_event_set (fdevents *ev, fdnode *fdn, int events)
806 {
807 ev_io *watcher = fdn->handler_ctx;
808 int ev_events = 0;
809
810 if (events & FDEVENT_IN) ev_events |= EV_READ;
811 if (events & FDEVENT_OUT) ev_events |= EV_WRITE;
812
813 if (!watcher) {
814 fdn->handler_ctx = watcher = calloc(1, sizeof(ev_io));
815 force_assert(watcher);
816 fdn->fde_ndx = fdn->fd;
817
818 ev_io_init(watcher, fdevent_libev_io_watcher_cb, fdn->fd, ev_events);
819 watcher->data = ev;
820 ev_io_start(ev->libev_loop, watcher);
821 }
822 else {
823 if ((watcher->events & (EV_READ | EV_WRITE)) != ev_events) {
824 ev_io_stop(ev->libev_loop, watcher);
825 ev_io_set(watcher, watcher->fd, ev_events);
826 ev_io_start(ev->libev_loop, watcher);
827 }
828 }
829
830 return 0;
831 }
832
833 static void
fdevent_libev_timeout_watcher_cb(struct ev_loop * loop,ev_timer * w,int revents)834 fdevent_libev_timeout_watcher_cb (struct ev_loop *loop, ev_timer *w, int revents)
835 {
836 UNUSED(loop);
837 UNUSED(w);
838 UNUSED(revents);
839 }
840
841 static ev_timer timeout_watcher;
842
843 static int
fdevent_libev_poll(fdevents * ev,int timeout_ms)844 fdevent_libev_poll (fdevents *ev, int timeout_ms)
845 {
846 timeout_watcher.repeat = (timeout_ms > 0) ? timeout_ms/1000.0 : 0.001;
847
848 ev_timer_again(ev->libev_loop, &timeout_watcher);
849 ev_run(ev->libev_loop, EVRUN_ONCE);
850
851 return 0;
852 }
853
854 __attribute_cold__
855 static int
fdevent_libev_reset(fdevents * ev)856 fdevent_libev_reset (fdevents *ev)
857 {
858 UNUSED(ev);
859 ev_default_fork();
860 return 0;
861 }
862
863 __attribute_cold__
864 static void
fdevent_libev_free(fdevents * ev)865 fdevent_libev_free (fdevents *ev)
866 {
867 UNUSED(ev);
868 }
869
870 __attribute_cold__
871 static int
fdevent_libev_init(fdevents * ev)872 fdevent_libev_init (fdevents *ev)
873 {
874 struct ev_timer * const timer = &timeout_watcher;
875 memset(timer, 0, sizeof(*timer));
876
877 ev->type = FDEVENT_HANDLER_LIBEV;
878 ev->event_set = fdevent_libev_event_set;
879 ev->event_del = fdevent_libev_event_del;
880 ev->poll = fdevent_libev_poll;
881 ev->reset = fdevent_libev_reset;
882 ev->free = fdevent_libev_free;
883
884 if (NULL == (ev->libev_loop = ev_default_loop(0))) return -1;
885
886 ev_timer_init(timer, fdevent_libev_timeout_watcher_cb, 0.0, 1.0);
887
888 return 0;
889 }
890
891 #endif /* FDEVENT_USE_LIBEV */
892
893
894 #ifdef FDEVENT_USE_POLL
895
896 #ifdef HAVE_POLL_H
897 #include <poll.h>
898 #else
899 #include <sys/poll.h>
900 #endif
901
902 static int
fdevent_poll_event_del(fdevents * ev,fdnode * fdn)903 fdevent_poll_event_del (fdevents *ev, fdnode *fdn)
904 {
905 int fd = fdn->fd;
906 int k = fdn->fde_ndx;
907 if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
908 return (errno = EINVAL, -1);
909
910 ev->pollfds[k].fd = -1;
911 /* ev->pollfds[k].events = 0; */
912 /* ev->pollfds[k].revents = 0; */
913
914 if (ev->unused.size == ev->unused.used) {
915 ev->unused.size += 16;
916 ev->unused.ptr = realloc(ev->unused.ptr,
917 sizeof(*(ev->unused.ptr)) * ev->unused.size);
918 force_assert(NULL != ev->unused.ptr);
919 }
920
921 ev->unused.ptr[ev->unused.used++] = k;
922
923 return 0;
924 }
925
926 static int
fdevent_poll_event_set(fdevents * ev,fdnode * fdn,int events)927 fdevent_poll_event_set (fdevents *ev, fdnode *fdn, int events)
928 {
929 int fd = fdn->fd;
930 int k = fdn->fde_ndx;
931
932 #ifndef POLLRDHUP
933 events &= ~FDEVENT_RDHUP;
934 #endif
935
936 if (k >= 0) {
937 if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
938 return (errno = EINVAL, -1);
939 ev->pollfds[k].events = events;
940 return 0;
941 }
942
943 if (ev->unused.used > 0) {
944 k = ev->unused.ptr[--ev->unused.used];
945 }
946 else {
947 if (ev->size == ev->used) {
948 ev->size += 16;
949 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
950 force_assert(NULL != ev->pollfds);
951 }
952
953 k = ev->used++;
954 }
955
956 fdn->fde_ndx = k;
957 ev->pollfds[k].fd = fd;
958 ev->pollfds[k].events = events;
959
960 return 0;
961 }
962
963 static int
fdevent_poll_poll(fdevents * ev,int timeout_ms)964 fdevent_poll_poll (fdevents *ev, int timeout_ms)
965 {
966 struct pollfd * const restrict pfds = ev->pollfds;
967 fdnode ** const fdarray = ev->fdarray;
968 const int n = poll(pfds, ev->used, timeout_ms);
969 for (int i = 0, m = 0; m < n; ++i) {
970 if (0 == pfds[i].revents) continue;
971 fdnode *fdn = fdarray[pfds[i].fd];
972 if (0 == ((uintptr_t)fdn & 0x3))
973 (*fdn->handler)(fdn->ctx, pfds[i].revents);
974 ++m;
975 }
976 return n;
977 }
978
979 __attribute_cold__
980 static void
fdevent_poll_free(fdevents * ev)981 fdevent_poll_free (fdevents *ev)
982 {
983 free(ev->pollfds);
984 if (ev->unused.ptr) free(ev->unused.ptr);
985 }
986
987 __attribute_cold__
988 static int
fdevent_poll_init(fdevents * ev)989 fdevent_poll_init (fdevents *ev)
990 {
991 force_assert(POLLIN == FDEVENT_IN);
992 force_assert(POLLPRI == FDEVENT_PRI);
993 force_assert(POLLOUT == FDEVENT_OUT);
994 force_assert(POLLERR == FDEVENT_ERR);
995 force_assert(POLLHUP == FDEVENT_HUP);
996 force_assert(POLLNVAL == FDEVENT_NVAL);
997 #ifdef POLLRDHUP
998 force_assert(POLLRDHUP == FDEVENT_RDHUP);
999 #endif
1000
1001 ev->type = FDEVENT_HANDLER_POLL;
1002 ev->event_set = fdevent_poll_event_set;
1003 ev->event_del = fdevent_poll_event_del;
1004 ev->poll = fdevent_poll_poll;
1005 ev->free = fdevent_poll_free;
1006 return 0;
1007 }
1008
1009 #endif /* FDEVENT_USE_POLL */
1010
1011
1012 #ifdef FDEVENT_USE_SELECT
1013
1014 #include "sys-time.h"
1015
1016 __attribute_cold__
1017 static int
fdevent_select_reset(fdevents * ev)1018 fdevent_select_reset (fdevents *ev)
1019 {
1020 FD_ZERO(&(ev->select_set_read));
1021 FD_ZERO(&(ev->select_set_write));
1022 FD_ZERO(&(ev->select_set_error));
1023 ev->select_max_fd = -1;
1024 return 0;
1025 }
1026
1027 static int
fdevent_select_event_del(fdevents * ev,fdnode * fdn)1028 fdevent_select_event_del (fdevents *ev, fdnode *fdn)
1029 {
1030 int fd = fdn->fd;
1031 FD_CLR(fd, &(ev->select_set_read));
1032 FD_CLR(fd, &(ev->select_set_write));
1033 FD_CLR(fd, &(ev->select_set_error));
1034 return 0;
1035 }
1036
1037 static int
fdevent_select_event_set(fdevents * ev,fdnode * fdn,int events)1038 fdevent_select_event_set (fdevents *ev, fdnode *fdn, int events)
1039 {
1040 int fd = fdn->fde_ndx = fdn->fd;
1041
1042 /* we should be protected by max-fds, but you never know */
1043 force_assert(fd < ((int)FD_SETSIZE));
1044
1045 if (events & FDEVENT_IN)
1046 FD_SET(fd, &(ev->select_set_read));
1047 else
1048 FD_CLR(fd, &(ev->select_set_read));
1049
1050 if (events & FDEVENT_OUT)
1051 FD_SET(fd, &(ev->select_set_write));
1052 else
1053 FD_CLR(fd, &(ev->select_set_write));
1054
1055 FD_SET(fd, &(ev->select_set_error));
1056
1057 if (fd > ev->select_max_fd) ev->select_max_fd = fd;
1058
1059 return 0;
1060 }
1061
1062 static int
fdevent_select_event_get_revent(const fdevents * ev,int ndx)1063 fdevent_select_event_get_revent (const fdevents *ev, int ndx)
1064 {
1065 int revents = 0;
1066 if (FD_ISSET(ndx, &ev->select_read)) revents |= FDEVENT_IN;
1067 if (FD_ISSET(ndx, &ev->select_write)) revents |= FDEVENT_OUT;
1068 if (FD_ISSET(ndx, &ev->select_error)) revents |= FDEVENT_ERR;
1069 return revents;
1070 }
1071
1072 static int
fdevent_select_event_next_fdndx(const fdevents * ev,int ndx)1073 fdevent_select_event_next_fdndx (const fdevents *ev, int ndx)
1074 {
1075 const int max_fd = ev->select_max_fd + 1;
1076 for (int i = (ndx < 0) ? 0 : ndx + 1; i < max_fd; ++i) {
1077 if (FD_ISSET(i, &(ev->select_read))) return i;
1078 if (FD_ISSET(i, &(ev->select_write))) return i;
1079 if (FD_ISSET(i, &(ev->select_error))) return i;
1080 }
1081
1082 return -1;
1083 }
1084
1085 static int
fdevent_select_poll(fdevents * ev,int timeout_ms)1086 fdevent_select_poll (fdevents *ev, int timeout_ms)
1087 {
1088 int n;
1089 struct timeval tv;
1090
1091 tv.tv_sec = timeout_ms / 1000;
1092 tv.tv_usec = (timeout_ms % 1000) * 1000;
1093
1094 ev->select_read = ev->select_set_read;
1095 ev->select_write = ev->select_set_write;
1096 ev->select_error = ev->select_set_error;
1097
1098 n = select(ev->select_max_fd + 1,
1099 &ev->select_read, &ev->select_write, &ev->select_error, &tv);
1100 for (int ndx = -1, i = 0; i < n; ++i) {
1101 fdnode *fdn;
1102 ndx = fdevent_select_event_next_fdndx(ev, ndx);
1103 if (-1 == ndx) break;
1104 fdn = ev->fdarray[ndx];
1105 if (0 == ((uintptr_t)fdn & 0x3)) {
1106 int revents = fdevent_select_event_get_revent(ev, ndx);
1107 (*fdn->handler)(fdn->ctx, revents);
1108 }
1109 }
1110 return n;
1111 }
1112
1113 __attribute_cold__
fdevent_select_init(fdevents * ev)1114 static int fdevent_select_init (fdevents *ev)
1115 {
1116 ev->type = FDEVENT_HANDLER_SELECT;
1117 ev->event_set = fdevent_select_event_set;
1118 ev->event_del = fdevent_select_event_del;
1119 ev->poll = fdevent_select_poll;
1120 ev->reset = fdevent_select_reset;
1121 return 0;
1122 }
1123
1124 #endif /* FDEVENT_USE_SELECT */
1125