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