xref: /lighttpd1.4/src/fdevent_impl.c (revision 32f0e26d)
1ec529177SGlenn Strauss #include "first.h"
2ec529177SGlenn Strauss 
3ec529177SGlenn Strauss #include "fdevent_impl.h"
4ec529177SGlenn Strauss #include "fdevent.h"
5ec529177SGlenn Strauss #include "buffer.h"
6ec529177SGlenn Strauss #include "log.h"
7ec529177SGlenn Strauss 
8ec529177SGlenn Strauss #include <sys/types.h>
9ec529177SGlenn Strauss #include <unistd.h>
10ec529177SGlenn Strauss #include <errno.h>
11ec529177SGlenn Strauss #include <stdlib.h>
12ec529177SGlenn Strauss #include <string.h>
13ec529177SGlenn Strauss 
14ec529177SGlenn Strauss #ifdef _WIN32
15ec529177SGlenn Strauss #include <winsock2.h>   /* closesocket */
16ec529177SGlenn Strauss #endif
17ec529177SGlenn Strauss 
187113dcb4SGlenn Strauss #ifdef FDEVENT_USE_LINUX_EPOLL
197113dcb4SGlenn Strauss __attribute_cold__
207113dcb4SGlenn Strauss static int fdevent_linux_sysepoll_init(struct fdevents *ev);
217113dcb4SGlenn Strauss #endif
227113dcb4SGlenn Strauss #ifdef FDEVENT_USE_FREEBSD_KQUEUE
237113dcb4SGlenn Strauss __attribute_cold__
247113dcb4SGlenn Strauss static int fdevent_freebsd_kqueue_init(struct fdevents *ev);
257113dcb4SGlenn Strauss #endif
267113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SOLARIS_PORT
277113dcb4SGlenn Strauss __attribute_cold__
287113dcb4SGlenn Strauss static int fdevent_solaris_port_init(struct fdevents *ev);
297113dcb4SGlenn Strauss #endif
307113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
317113dcb4SGlenn Strauss __attribute_cold__
327113dcb4SGlenn Strauss static int fdevent_solaris_devpoll_init(struct fdevents *ev);
337113dcb4SGlenn Strauss #endif
347113dcb4SGlenn Strauss #ifdef FDEVENT_USE_POLL
357113dcb4SGlenn Strauss __attribute_cold__
367113dcb4SGlenn Strauss static int fdevent_poll_init(struct fdevents *ev);
377113dcb4SGlenn Strauss #endif
387113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SELECT
397113dcb4SGlenn Strauss __attribute_cold__
407113dcb4SGlenn Strauss static int fdevent_select_init(struct fdevents *ev);
417113dcb4SGlenn Strauss #endif
427113dcb4SGlenn Strauss 
437113dcb4SGlenn Strauss 
44ec529177SGlenn Strauss int
fdevent_config(const char ** event_handler_name,log_error_st * errh)45ec529177SGlenn Strauss fdevent_config (const char **event_handler_name, log_error_st *errh)
46ec529177SGlenn Strauss {
47ec529177SGlenn Strauss     static const struct ev_map { fdevent_handler_t et; const char *name; }
48ec529177SGlenn Strauss       event_handlers[] =
49ec529177SGlenn Strauss     {
50ec529177SGlenn Strauss         /* - epoll is most reliable
51ec529177SGlenn Strauss          * - select works everywhere
52ec529177SGlenn Strauss          */
53ec529177SGlenn Strauss       #ifdef FDEVENT_USE_LINUX_EPOLL
54ec529177SGlenn Strauss         { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
55ec529177SGlenn Strauss         { FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" },
56ec529177SGlenn Strauss       #endif
57ec529177SGlenn Strauss       #ifdef FDEVENT_USE_SOLARIS_PORT
58ec529177SGlenn Strauss         { FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
59ec529177SGlenn Strauss       #endif
60ec529177SGlenn Strauss       #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
61ec529177SGlenn Strauss         { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
62ec529177SGlenn Strauss       #endif
63ec529177SGlenn Strauss       #ifdef FDEVENT_USE_FREEBSD_KQUEUE
64ec529177SGlenn Strauss         { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
65ec529177SGlenn Strauss         { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
66ec529177SGlenn Strauss       #endif
67ec529177SGlenn Strauss       #ifdef FDEVENT_USE_POLL
68ec529177SGlenn Strauss         { FDEVENT_HANDLER_POLL,           "poll" },
69ec529177SGlenn Strauss       #endif
70ec529177SGlenn Strauss       #ifdef FDEVENT_USE_SELECT
71ec529177SGlenn Strauss         { FDEVENT_HANDLER_SELECT,         "select" },
72ec529177SGlenn Strauss       #endif
73ec529177SGlenn Strauss         { FDEVENT_HANDLER_UNSET,          NULL }
74ec529177SGlenn Strauss     };
75ec529177SGlenn Strauss 
76ec529177SGlenn Strauss     const char *event_handler = *event_handler_name;
77ec529177SGlenn Strauss     fdevent_handler_t et = FDEVENT_HANDLER_UNSET;
78ec529177SGlenn Strauss 
79ec529177SGlenn Strauss     if (NULL != event_handler && 0 == strcmp(event_handler, "libev"))
80ec529177SGlenn Strauss         event_handler = NULL;
81ec529177SGlenn Strauss   #ifdef FDEVENT_USE_POLL
82ec529177SGlenn Strauss     if (NULL != event_handler && 0 == strcmp(event_handler, "select"))
83ec529177SGlenn Strauss         event_handler = "poll";
84ec529177SGlenn Strauss   #endif
85ec529177SGlenn Strauss 
86ec529177SGlenn Strauss     if (NULL == event_handler) {
87ec529177SGlenn Strauss         /* choose a good default
88ec529177SGlenn Strauss          *
89ec529177SGlenn Strauss          * the event_handler list is sorted by 'goodness'
90ec529177SGlenn Strauss          * taking the first available should be the best solution
91ec529177SGlenn Strauss          */
92ec529177SGlenn Strauss         et = event_handlers[0].et;
93ec529177SGlenn Strauss         *event_handler_name = event_handlers[0].name;
94ec529177SGlenn Strauss 
95ec529177SGlenn Strauss         if (FDEVENT_HANDLER_UNSET == et) {
96ec529177SGlenn Strauss             log_error(errh, __FILE__, __LINE__,
97ec529177SGlenn Strauss               "sorry, there is no event handler for this system");
98ec529177SGlenn Strauss 
99ec529177SGlenn Strauss             return -1;
100ec529177SGlenn Strauss         }
101ec529177SGlenn Strauss     }
102ec529177SGlenn Strauss     else {
103ec529177SGlenn Strauss         /*
104ec529177SGlenn Strauss          * User override
105ec529177SGlenn Strauss          */
106ec529177SGlenn Strauss 
107ec529177SGlenn Strauss         for (uint32_t i = 0; event_handlers[i].name; ++i) {
108ec529177SGlenn Strauss             if (0 == strcmp(event_handlers[i].name, event_handler)) {
109ec529177SGlenn Strauss                 et = event_handlers[i].et;
110ec529177SGlenn Strauss                 break;
111ec529177SGlenn Strauss             }
112ec529177SGlenn Strauss         }
113ec529177SGlenn Strauss 
114ec529177SGlenn Strauss         if (FDEVENT_HANDLER_UNSET == et) {
115ec529177SGlenn Strauss             log_error(errh, __FILE__, __LINE__,
116ec529177SGlenn Strauss               "the selected event-handler in unknown or not supported: %s",
117ec529177SGlenn Strauss               event_handler);
118ec529177SGlenn Strauss             return -1;
119ec529177SGlenn Strauss         }
120ec529177SGlenn Strauss     }
121ec529177SGlenn Strauss 
122ec529177SGlenn Strauss     return et;
123ec529177SGlenn Strauss }
124ec529177SGlenn Strauss 
125ec529177SGlenn Strauss 
126ec529177SGlenn Strauss const char *
fdevent_show_event_handlers(void)127ec529177SGlenn Strauss fdevent_show_event_handlers (void)
128ec529177SGlenn Strauss {
129ec529177SGlenn Strauss     return
130ec529177SGlenn Strauss       "\nEvent Handlers:\n\n"
131ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SELECT
132ec529177SGlenn Strauss       "\t+ select (generic)\n"
133ec529177SGlenn Strauss      #else
134ec529177SGlenn Strauss       "\t- select (generic)\n"
135ec529177SGlenn Strauss      #endif
136ec529177SGlenn Strauss      #ifdef FDEVENT_USE_POLL
137ec529177SGlenn Strauss       "\t+ poll (Unix)\n"
138ec529177SGlenn Strauss      #else
139ec529177SGlenn Strauss       "\t- poll (Unix)\n"
140ec529177SGlenn Strauss      #endif
141ec529177SGlenn Strauss      #ifdef FDEVENT_USE_LINUX_EPOLL
142ec529177SGlenn Strauss       "\t+ epoll (Linux)\n"
143ec529177SGlenn Strauss      #else
144ec529177SGlenn Strauss       "\t- epoll (Linux)\n"
145ec529177SGlenn Strauss      #endif
146ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
147ec529177SGlenn Strauss       "\t+ /dev/poll (Solaris)\n"
148ec529177SGlenn Strauss      #else
149ec529177SGlenn Strauss       "\t- /dev/poll (Solaris)\n"
150ec529177SGlenn Strauss      #endif
151ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SOLARIS_PORT
152ec529177SGlenn Strauss       "\t+ eventports (Solaris)\n"
153ec529177SGlenn Strauss      #else
154ec529177SGlenn Strauss       "\t- eventports (Solaris)\n"
155ec529177SGlenn Strauss      #endif
156ec529177SGlenn Strauss      #ifdef FDEVENT_USE_FREEBSD_KQUEUE
157ec529177SGlenn Strauss       "\t+ kqueue (FreeBSD)\n"
158ec529177SGlenn Strauss      #else
159ec529177SGlenn Strauss       "\t- kqueue (FreeBSD)\n"
160ec529177SGlenn Strauss      #endif
161ec529177SGlenn Strauss       ;
162ec529177SGlenn Strauss }
163ec529177SGlenn Strauss 
164ec529177SGlenn Strauss 
165ec529177SGlenn Strauss fdevents *
fdevent_init(const char * event_handler,int * max_fds,int * cur_fds,log_error_st * errh)166ec529177SGlenn Strauss fdevent_init (const char *event_handler, int *max_fds, int *cur_fds, log_error_st *errh)
167ec529177SGlenn Strauss {
168ec529177SGlenn Strauss     fdevents *ev;
169ec529177SGlenn Strauss     uint32_t maxfds = (0 != *max_fds)
170ec529177SGlenn Strauss       ? (uint32_t)*max_fds
171ec529177SGlenn Strauss       : 4096;
172ec529177SGlenn Strauss     int type = fdevent_config(&event_handler, errh);
173ec529177SGlenn Strauss     if (type <= 0) return NULL;
174ec529177SGlenn Strauss 
175ec529177SGlenn Strauss     fdevent_socket_nb_cloexec_init();
176ec529177SGlenn Strauss 
177ec529177SGlenn Strauss       #ifdef FDEVENT_USE_SELECT
178ec529177SGlenn Strauss     /* select limits itself
179ec529177SGlenn Strauss      * as it is a hard limit and will lead to a segfault we add some safety
180ec529177SGlenn Strauss      * */
181ec529177SGlenn Strauss     if (type == FDEVENT_HANDLER_SELECT) {
182ec529177SGlenn Strauss         if (maxfds > (uint32_t)FD_SETSIZE - 200)
183ec529177SGlenn Strauss             maxfds = (uint32_t)FD_SETSIZE - 200;
184ec529177SGlenn Strauss     }
185ec529177SGlenn Strauss       #endif
186ec529177SGlenn Strauss     *max_fds = (int)maxfds;
187ec529177SGlenn Strauss     ++maxfds; /*(+1 for event-handler fd)*/
188ec529177SGlenn Strauss 
1895e14db43SGlenn Strauss     ev = ck_calloc(1, sizeof(*ev));
190ec529177SGlenn Strauss     ev->errh = errh;
191ec529177SGlenn Strauss     ev->cur_fds = cur_fds;
192ec529177SGlenn Strauss     ev->event_handler = event_handler;
1935e14db43SGlenn Strauss     ev->fdarray = ck_calloc(maxfds, sizeof(*ev->fdarray));
194ec529177SGlenn Strauss     ev->maxfds = maxfds;
195ec529177SGlenn Strauss 
196ec529177SGlenn Strauss     switch(type) {
197ec529177SGlenn Strauss      #ifdef FDEVENT_USE_POLL
198ec529177SGlenn Strauss       case FDEVENT_HANDLER_POLL:
199ec529177SGlenn Strauss         if (0 == fdevent_poll_init(ev)) return ev;
200ec529177SGlenn Strauss         break;
201ec529177SGlenn Strauss      #endif
202ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SELECT
203ec529177SGlenn Strauss       case FDEVENT_HANDLER_SELECT:
204ec529177SGlenn Strauss         if (0 == fdevent_select_init(ev)) return ev;
205ec529177SGlenn Strauss         break;
206ec529177SGlenn Strauss      #endif
207ec529177SGlenn Strauss      #ifdef FDEVENT_USE_LINUX_EPOLL
208ec529177SGlenn Strauss       case FDEVENT_HANDLER_LINUX_SYSEPOLL:
209ec529177SGlenn Strauss         if (0 == fdevent_linux_sysepoll_init(ev)) return ev;
210ec529177SGlenn Strauss         break;
211ec529177SGlenn Strauss      #endif
212ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
213ec529177SGlenn Strauss       case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
214ec529177SGlenn Strauss         if (0 == fdevent_solaris_devpoll_init(ev)) return ev;
215ec529177SGlenn Strauss         break;
216ec529177SGlenn Strauss      #endif
217ec529177SGlenn Strauss      #ifdef FDEVENT_USE_SOLARIS_PORT
218ec529177SGlenn Strauss       case FDEVENT_HANDLER_SOLARIS_PORT:
219ec529177SGlenn Strauss         if (0 == fdevent_solaris_port_init(ev)) return ev;
220ec529177SGlenn Strauss         break;
221ec529177SGlenn Strauss      #endif
222ec529177SGlenn Strauss      #ifdef FDEVENT_USE_FREEBSD_KQUEUE
223ec529177SGlenn Strauss       case FDEVENT_HANDLER_FREEBSD_KQUEUE:
224ec529177SGlenn Strauss         if (0 == fdevent_freebsd_kqueue_init(ev)) return ev;
225ec529177SGlenn Strauss         break;
226ec529177SGlenn Strauss      #endif
227ec529177SGlenn Strauss       /*case FDEVENT_HANDLER_UNSET:*/
228ec529177SGlenn Strauss       default:
229ec529177SGlenn Strauss         break;
230ec529177SGlenn Strauss     }
231ec529177SGlenn Strauss 
232ec529177SGlenn Strauss     free(ev->fdarray);
233ec529177SGlenn Strauss     free(ev);
234ec529177SGlenn Strauss 
235ec529177SGlenn Strauss     log_error(errh, __FILE__, __LINE__,
236ec529177SGlenn Strauss       "event-handler failed: %s; "
237ec529177SGlenn Strauss       "try to set server.event-handler = \"poll\" or \"select\"",
238ec529177SGlenn Strauss       event_handler);
239ec529177SGlenn Strauss     return NULL;
240ec529177SGlenn Strauss }
241ec529177SGlenn Strauss 
242ec529177SGlenn Strauss 
243ec529177SGlenn Strauss void
fdevent_free(fdevents * ev)244ec529177SGlenn Strauss fdevent_free (fdevents *ev)
245ec529177SGlenn Strauss {
246ec529177SGlenn Strauss     if (!ev) return;
247ec529177SGlenn Strauss     if (ev->free) ev->free(ev);
248ec529177SGlenn Strauss 
249ec529177SGlenn Strauss     for (uint32_t i = 0; i < ev->maxfds; ++i) {
250ec529177SGlenn Strauss         /* (fdevent_sched_run() should already have been run,
251ec529177SGlenn Strauss          *  but take reasonable precautions anyway) */
252ec529177SGlenn Strauss         if (ev->fdarray[i])
253ec529177SGlenn Strauss             free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3));
254ec529177SGlenn Strauss     }
255ec529177SGlenn Strauss 
256ec529177SGlenn Strauss     free(ev->fdarray);
257ec529177SGlenn Strauss     free(ev);
258ec529177SGlenn Strauss }
259ec529177SGlenn Strauss 
260ec529177SGlenn Strauss 
261ec529177SGlenn Strauss int
fdevent_reset(fdevents * ev)262ec529177SGlenn Strauss fdevent_reset (fdevents *ev)
263ec529177SGlenn Strauss {
264ec529177SGlenn Strauss     int rc = (NULL != ev->reset) ? ev->reset(ev) : 0;
265ec529177SGlenn Strauss     if (-1 == rc) {
266ec529177SGlenn Strauss         log_error(ev->errh, __FILE__, __LINE__,
267ec529177SGlenn Strauss           "event-handler failed: %s; "
268ec529177SGlenn Strauss           "try to set server.event-handler = \"poll\" or \"select\"",
269ec529177SGlenn Strauss           ev->event_handler ? ev->event_handler : "");
270ec529177SGlenn Strauss     }
271ec529177SGlenn Strauss     return rc;
272ec529177SGlenn Strauss }
273ec529177SGlenn Strauss 
274ec529177SGlenn Strauss 
275ec529177SGlenn Strauss static void
fdevent_sched_run(fdevents * const ev)276ec529177SGlenn Strauss fdevent_sched_run (fdevents * const ev)
277ec529177SGlenn Strauss {
278ec529177SGlenn Strauss     for (fdnode *fdn = ev->pendclose; fdn; ) {
279f0786a75SGlenn Strauss         int fd = fdn->fd;
280ec529177SGlenn Strauss       #ifdef _WIN32
281f0786a75SGlenn Strauss         if (0 != closesocket(fd)) /* WSAPoll() valid only on SOCKET */
282ec529177SGlenn Strauss       #else
283f0786a75SGlenn Strauss         if (0 != close(fd))
284ec529177SGlenn Strauss       #endif
285ec529177SGlenn Strauss             log_perror(ev->errh, __FILE__, __LINE__, "close failed %d", fd);
286f0786a75SGlenn Strauss         else
287ec529177SGlenn Strauss             --(*ev->cur_fds);
288ec529177SGlenn Strauss 
289ec529177SGlenn Strauss         fdnode * const fdn_tmp = fdn;
290ec529177SGlenn Strauss         fdn = (fdnode *)fdn->ctx; /* next */
291ec529177SGlenn Strauss         /*(fdevent_unregister)*/
292ec529177SGlenn Strauss         ev->fdarray[fd] = NULL;
293f0786a75SGlenn Strauss         free(fdn_tmp); /*fdnode_free(fdn_tmp);*/
294ec529177SGlenn Strauss     }
295ec529177SGlenn Strauss     ev->pendclose = NULL;
296ec529177SGlenn Strauss }
297ec529177SGlenn Strauss 
298ec529177SGlenn Strauss 
299ec529177SGlenn Strauss int
fdevent_poll(fdevents * const ev,const int timeout_ms)300ec529177SGlenn Strauss fdevent_poll (fdevents * const ev, const int timeout_ms)
301ec529177SGlenn Strauss {
302b376934bSGlenn Strauss     const int n = ev->poll(ev, ev->pendclose ? 0 : timeout_ms);
303ec529177SGlenn Strauss     if (n >= 0)
304ec529177SGlenn Strauss         fdevent_sched_run(ev);
305ec529177SGlenn Strauss     else if (errno != EINTR)
306ec529177SGlenn Strauss         log_perror(ev->errh, __FILE__, __LINE__, "fdevent_poll failed");
307ec529177SGlenn Strauss     return n;
308ec529177SGlenn Strauss }
3097113dcb4SGlenn Strauss 
3107113dcb4SGlenn Strauss 
3117113dcb4SGlenn Strauss #ifdef FDEVENT_USE_LINUX_EPOLL
3127113dcb4SGlenn Strauss 
3137113dcb4SGlenn Strauss #include <sys/epoll.h>
3147113dcb4SGlenn Strauss 
3157113dcb4SGlenn Strauss static int
fdevent_linux_sysepoll_event_del(fdevents * ev,fdnode * fdn)3167113dcb4SGlenn Strauss fdevent_linux_sysepoll_event_del (fdevents *ev, fdnode *fdn)
3177113dcb4SGlenn Strauss {
3187113dcb4SGlenn Strauss     return epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fdn->fd, NULL);
3197113dcb4SGlenn Strauss }
3207113dcb4SGlenn Strauss 
3217113dcb4SGlenn Strauss static int
fdevent_linux_sysepoll_event_set(fdevents * ev,fdnode * fdn,int events)3227113dcb4SGlenn Strauss fdevent_linux_sysepoll_event_set (fdevents *ev, fdnode *fdn, int events)
3237113dcb4SGlenn Strauss {
3247113dcb4SGlenn Strauss     int op = (-1 == fdn->fde_ndx) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
3257113dcb4SGlenn Strauss     int fd = fdn->fde_ndx = fdn->fd;
3267113dcb4SGlenn Strauss     struct epoll_event ep;
3277113dcb4SGlenn Strauss   #ifndef EPOLLRDHUP
3287113dcb4SGlenn Strauss     events &= ~FDEVENT_RDHUP;
3297113dcb4SGlenn Strauss   #endif
3307113dcb4SGlenn Strauss     ep.events = events | EPOLLERR | EPOLLHUP;
3317113dcb4SGlenn Strauss     ep.data.ptr = fdn;
3327113dcb4SGlenn Strauss     return epoll_ctl(ev->epoll_fd, op, fd, &ep);
3337113dcb4SGlenn Strauss }
3347113dcb4SGlenn Strauss 
3357113dcb4SGlenn Strauss static int
fdevent_linux_sysepoll_poll(fdevents * const ev,int timeout_ms)3367113dcb4SGlenn Strauss fdevent_linux_sysepoll_poll (fdevents * const ev, int timeout_ms)
3377113dcb4SGlenn Strauss {
3387113dcb4SGlenn Strauss     struct epoll_event * const restrict epoll_events = ev->epoll_events;
3397113dcb4SGlenn Strauss     int n = epoll_wait(ev->epoll_fd, epoll_events, ev->maxfds, timeout_ms);
3407113dcb4SGlenn Strauss     for (int i = 0; i < n; ++i) {
3417113dcb4SGlenn Strauss         fdnode * const fdn = (fdnode *)epoll_events[i].data.ptr;
3427113dcb4SGlenn Strauss         int revents = epoll_events[i].events;
3437113dcb4SGlenn Strauss         if ((fdevent_handler)NULL != fdn->handler)
3447113dcb4SGlenn Strauss             (*fdn->handler)(fdn->ctx, revents);
3457113dcb4SGlenn Strauss     }
3467113dcb4SGlenn Strauss     return n;
3477113dcb4SGlenn Strauss }
3487113dcb4SGlenn Strauss 
3497113dcb4SGlenn Strauss __attribute_cold__
3507113dcb4SGlenn Strauss static void
fdevent_linux_sysepoll_free(fdevents * ev)3517113dcb4SGlenn Strauss fdevent_linux_sysepoll_free (fdevents *ev)
3527113dcb4SGlenn Strauss {
3537113dcb4SGlenn Strauss     close(ev->epoll_fd);
3547113dcb4SGlenn Strauss     free(ev->epoll_events);
3557113dcb4SGlenn Strauss }
3567113dcb4SGlenn Strauss 
3577113dcb4SGlenn Strauss __attribute_cold__
3587113dcb4SGlenn Strauss static int
fdevent_linux_sysepoll_init(fdevents * ev)3597113dcb4SGlenn Strauss fdevent_linux_sysepoll_init (fdevents *ev)
3607113dcb4SGlenn Strauss {
3617113dcb4SGlenn Strauss     force_assert(EPOLLIN    == FDEVENT_IN);
3627113dcb4SGlenn Strauss     force_assert(EPOLLPRI   == FDEVENT_PRI);
3637113dcb4SGlenn Strauss     force_assert(EPOLLOUT   == FDEVENT_OUT);
3647113dcb4SGlenn Strauss     force_assert(EPOLLERR   == FDEVENT_ERR);
3657113dcb4SGlenn Strauss     force_assert(EPOLLHUP   == FDEVENT_HUP);
3667113dcb4SGlenn Strauss   #ifdef EPOLLRDHUP
3677113dcb4SGlenn Strauss     force_assert(EPOLLRDHUP == FDEVENT_RDHUP);
3687113dcb4SGlenn Strauss   #endif
3697113dcb4SGlenn Strauss 
3707113dcb4SGlenn Strauss     ev->type      = FDEVENT_HANDLER_LINUX_SYSEPOLL;
3717113dcb4SGlenn Strauss     ev->event_set = fdevent_linux_sysepoll_event_set;
3727113dcb4SGlenn Strauss     ev->event_del = fdevent_linux_sysepoll_event_del;
3737113dcb4SGlenn Strauss     ev->poll      = fdevent_linux_sysepoll_poll;
3747113dcb4SGlenn Strauss     ev->free      = fdevent_linux_sysepoll_free;
3757113dcb4SGlenn Strauss 
3767113dcb4SGlenn Strauss   #ifdef EPOLL_CLOEXEC
3777113dcb4SGlenn Strauss     if (-1 == (ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC))) return -1;
3787113dcb4SGlenn Strauss   #else
3797113dcb4SGlenn Strauss     if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) return -1;
3807113dcb4SGlenn Strauss     fdevent_setfd_cloexec(ev->epoll_fd);
3817113dcb4SGlenn Strauss   #endif
3827113dcb4SGlenn Strauss 
3835e14db43SGlenn Strauss     ev->epoll_events = ck_calloc(ev->maxfds, sizeof(*ev->epoll_events));
3847113dcb4SGlenn Strauss 
3857113dcb4SGlenn Strauss     return 0;
3867113dcb4SGlenn Strauss }
3877113dcb4SGlenn Strauss 
3887113dcb4SGlenn Strauss #endif /* FDEVENT_USE_LINUX_EPOLL */
3897113dcb4SGlenn Strauss 
3907113dcb4SGlenn Strauss 
3917113dcb4SGlenn Strauss #ifdef FDEVENT_USE_FREEBSD_KQUEUE
3927113dcb4SGlenn Strauss 
3937113dcb4SGlenn Strauss #include <sys/event.h>
3947113dcb4SGlenn Strauss #include <sys/time.h>
3957113dcb4SGlenn Strauss #include <fcntl.h>
3967113dcb4SGlenn Strauss 
3977113dcb4SGlenn Strauss static int
fdevent_freebsd_kqueue_event_del(fdevents * ev,fdnode * fdn)3987113dcb4SGlenn Strauss fdevent_freebsd_kqueue_event_del (fdevents *ev, fdnode *fdn)
3997113dcb4SGlenn Strauss {
4007113dcb4SGlenn Strauss     struct kevent kev[2];
4017113dcb4SGlenn Strauss     struct timespec ts = {0, 0};
4027113dcb4SGlenn Strauss     int fd = fdn->fd;
4037113dcb4SGlenn Strauss     int n = 0;
4047113dcb4SGlenn Strauss     int oevents = fdn->events;
4057113dcb4SGlenn Strauss 
4067113dcb4SGlenn Strauss     if (oevents & FDEVENT_IN)  {
4077113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
4087113dcb4SGlenn Strauss         n++;
4097113dcb4SGlenn Strauss     }
4107113dcb4SGlenn Strauss     if (oevents & FDEVENT_OUT)  {
4117113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
4127113dcb4SGlenn Strauss         n++;
4137113dcb4SGlenn Strauss     }
4147113dcb4SGlenn Strauss 
4157113dcb4SGlenn Strauss     return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
4167113dcb4SGlenn Strauss     /*(kevent() changelist still processed on EINTR,
4177113dcb4SGlenn Strauss      * but EINTR should not be received since 0 == nevents)*/
4187113dcb4SGlenn Strauss }
4197113dcb4SGlenn Strauss 
4207113dcb4SGlenn Strauss static int
fdevent_freebsd_kqueue_event_set(fdevents * ev,fdnode * fdn,int events)4217113dcb4SGlenn Strauss fdevent_freebsd_kqueue_event_set (fdevents *ev, fdnode *fdn, int events)
4227113dcb4SGlenn Strauss {
4237113dcb4SGlenn Strauss     struct kevent kev[2];
4247113dcb4SGlenn Strauss     struct timespec ts = {0, 0};
4257113dcb4SGlenn Strauss     int fd = fdn->fde_ndx = fdn->fd;
4267113dcb4SGlenn Strauss     int n = 0;
4277113dcb4SGlenn Strauss     int oevents = fdn->events;
4287113dcb4SGlenn Strauss     int addevents = events & ~oevents;
4297113dcb4SGlenn Strauss     int delevents = ~events & oevents;
4307113dcb4SGlenn Strauss 
4317113dcb4SGlenn Strauss     if (addevents & FDEVENT_IN)  {
4327113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn);
4337113dcb4SGlenn Strauss         n++;
4347113dcb4SGlenn Strauss     }
4357113dcb4SGlenn Strauss     else if (delevents & FDEVENT_IN) {
4367113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
4377113dcb4SGlenn Strauss         n++;
4387113dcb4SGlenn Strauss     }
4397113dcb4SGlenn Strauss 
4407113dcb4SGlenn Strauss     if (addevents & FDEVENT_OUT)  {
4417113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn);
4427113dcb4SGlenn Strauss         n++;
4437113dcb4SGlenn Strauss     }
4447113dcb4SGlenn Strauss     else if (delevents & FDEVENT_OUT) {
4457113dcb4SGlenn Strauss         EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
4467113dcb4SGlenn Strauss         n++;
4477113dcb4SGlenn Strauss     }
4487113dcb4SGlenn Strauss 
4497113dcb4SGlenn Strauss     return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
4507113dcb4SGlenn Strauss     /*(kevent() changelist still processed on EINTR,
4517113dcb4SGlenn Strauss      * but EINTR should not be received since 0 == nevents)*/
4527113dcb4SGlenn Strauss }
4537113dcb4SGlenn Strauss 
4547113dcb4SGlenn Strauss static int
fdevent_freebsd_kqueue_poll(fdevents * const ev,int timeout_ms)4557113dcb4SGlenn Strauss fdevent_freebsd_kqueue_poll (fdevents * const ev, int timeout_ms)
4567113dcb4SGlenn Strauss {
4577113dcb4SGlenn Strauss     struct timespec ts;
4587113dcb4SGlenn Strauss     ts.tv_sec  = timeout_ms / 1000;
4597113dcb4SGlenn Strauss     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
4607113dcb4SGlenn Strauss 
4617113dcb4SGlenn Strauss     struct kevent * const restrict kq_results = ev->kq_results;
4627113dcb4SGlenn Strauss     const int n = kevent(ev->kq_fd, NULL, 0, kq_results, ev->maxfds, &ts);
4637113dcb4SGlenn Strauss 
4647113dcb4SGlenn Strauss     for (int i = 0; i < n; ++i) {
4657113dcb4SGlenn Strauss         fdnode * const fdn = (fdnode *)kq_results[i].udata;
4667113dcb4SGlenn Strauss         int filt = kq_results[i].filter;
4677113dcb4SGlenn Strauss         int e = kq_results[i].flags;
4687113dcb4SGlenn Strauss         if ((fdevent_handler)NULL != fdn->handler) {
4697113dcb4SGlenn Strauss             int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT;
4707113dcb4SGlenn Strauss             if (e & EV_EOF)
4717113dcb4SGlenn Strauss                 revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP);
4727113dcb4SGlenn Strauss             if (e & EV_ERROR)
4737113dcb4SGlenn Strauss                 revents |= FDEVENT_ERR;
4747113dcb4SGlenn Strauss             (*fdn->handler)(fdn->ctx, revents);
4757113dcb4SGlenn Strauss         }
4767113dcb4SGlenn Strauss     }
4777113dcb4SGlenn Strauss     return n;
4787113dcb4SGlenn Strauss }
4797113dcb4SGlenn Strauss 
4807113dcb4SGlenn Strauss __attribute_cold__
4817113dcb4SGlenn Strauss static int
fdevent_freebsd_kqueue_reset(fdevents * ev)4827113dcb4SGlenn Strauss fdevent_freebsd_kqueue_reset (fdevents *ev)
4837113dcb4SGlenn Strauss {
4847113dcb4SGlenn Strauss   #ifdef __NetBSD__
4857113dcb4SGlenn Strauss     ev->kq_fd = kqueue1(O_NONBLOCK|O_CLOEXEC|O_NOSIGPIPE);
4867113dcb4SGlenn Strauss     return (-1 != ev->kq_fd) ? 0 : -1;
4877113dcb4SGlenn Strauss   #else
4887113dcb4SGlenn Strauss     ev->kq_fd = kqueue();
4897113dcb4SGlenn Strauss     if (-1 == ev->kq_fd) return -1;
4907113dcb4SGlenn Strauss     fdevent_setfd_cloexec(ev->kq_fd);
4917113dcb4SGlenn Strauss     return 0;
4927113dcb4SGlenn Strauss   #endif
4937113dcb4SGlenn Strauss }
4947113dcb4SGlenn Strauss 
4957113dcb4SGlenn Strauss __attribute_cold__
4967113dcb4SGlenn Strauss static void
fdevent_freebsd_kqueue_free(fdevents * ev)4977113dcb4SGlenn Strauss fdevent_freebsd_kqueue_free (fdevents *ev)
4987113dcb4SGlenn Strauss {
4997113dcb4SGlenn Strauss     close(ev->kq_fd);
5007113dcb4SGlenn Strauss     free(ev->kq_results);
5017113dcb4SGlenn Strauss }
5027113dcb4SGlenn Strauss 
5037113dcb4SGlenn Strauss __attribute_cold__
5047113dcb4SGlenn Strauss static int
fdevent_freebsd_kqueue_init(fdevents * ev)5057113dcb4SGlenn Strauss fdevent_freebsd_kqueue_init (fdevents *ev)
5067113dcb4SGlenn Strauss {
5077113dcb4SGlenn Strauss     ev->type       = FDEVENT_HANDLER_FREEBSD_KQUEUE;
5087113dcb4SGlenn Strauss     ev->event_set  = fdevent_freebsd_kqueue_event_set;
5097113dcb4SGlenn Strauss     ev->event_del  = fdevent_freebsd_kqueue_event_del;
5107113dcb4SGlenn Strauss     ev->poll       = fdevent_freebsd_kqueue_poll;
5117113dcb4SGlenn Strauss     ev->reset      = fdevent_freebsd_kqueue_reset;
5127113dcb4SGlenn Strauss     ev->free       = fdevent_freebsd_kqueue_free;
5137113dcb4SGlenn Strauss     ev->kq_fd      = -1;
5145e14db43SGlenn Strauss     ev->kq_results = ck_calloc(ev->maxfds, sizeof(*ev->kq_results));
5157113dcb4SGlenn Strauss     return 0;
5167113dcb4SGlenn Strauss }
5177113dcb4SGlenn Strauss 
5187113dcb4SGlenn Strauss #endif /* FDEVENT_USE_FREEBSD_KQUEUE */
5197113dcb4SGlenn Strauss 
5207113dcb4SGlenn Strauss 
5217113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SOLARIS_PORT
5227113dcb4SGlenn Strauss 
5237113dcb4SGlenn Strauss #include <sys/poll.h>
5247113dcb4SGlenn Strauss #include <fcntl.h>
5257113dcb4SGlenn Strauss 
5267113dcb4SGlenn Strauss static int
fdevent_solaris_port_event_del(fdevents * ev,fdnode * fdn)5277113dcb4SGlenn Strauss fdevent_solaris_port_event_del (fdevents *ev, fdnode *fdn)
5287113dcb4SGlenn Strauss {
5297113dcb4SGlenn Strauss     return port_dissociate(ev->port_fd, PORT_SOURCE_FD, fdn->fd);
5307113dcb4SGlenn Strauss }
5317113dcb4SGlenn Strauss 
5327113dcb4SGlenn Strauss static int
fdevent_solaris_port_event_set(fdevents * ev,fdnode * fdn,int events)5337113dcb4SGlenn Strauss fdevent_solaris_port_event_set (fdevents *ev, fdnode *fdn, int events)
5347113dcb4SGlenn Strauss {
5357113dcb4SGlenn Strauss     int fd = fdn->fde_ndx = fdn->fd;
5367113dcb4SGlenn Strauss     intptr_t ud = events & (POLLIN|POLLOUT);
5377113dcb4SGlenn Strauss     return port_associate(ev->port_fd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud);
5387113dcb4SGlenn Strauss }
5397113dcb4SGlenn Strauss 
5407113dcb4SGlenn Strauss /* if there is any error it will return the return values of port_getn,
5417113dcb4SGlenn Strauss  * otherwise it will return number of events */
5427113dcb4SGlenn Strauss static int
fdevent_solaris_port_poll(fdevents * ev,int timeout_ms)5437113dcb4SGlenn Strauss fdevent_solaris_port_poll (fdevents *ev, int timeout_ms)
5447113dcb4SGlenn Strauss {
5457113dcb4SGlenn Strauss     const int pfd = ev->port_fd;
5467113dcb4SGlenn Strauss     int ret;
5477113dcb4SGlenn Strauss     unsigned int available_events, wait_for_events = 0;
5487113dcb4SGlenn Strauss 
5497113dcb4SGlenn Strauss     struct timespec  timeout;
5507113dcb4SGlenn Strauss 
5517113dcb4SGlenn Strauss     timeout.tv_sec  = timeout_ms/1000L;
5527113dcb4SGlenn Strauss     timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L;
5537113dcb4SGlenn Strauss 
5547113dcb4SGlenn Strauss     /* get the number of file descriptors with events */
5557113dcb4SGlenn Strauss     if ((ret = port_getn(pfd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret;
5567113dcb4SGlenn Strauss 
5577113dcb4SGlenn Strauss     /* wait for at least one event */
5587113dcb4SGlenn Strauss     if (0 == wait_for_events) wait_for_events = 1;
5597113dcb4SGlenn Strauss 
5607113dcb4SGlenn Strauss     available_events = wait_for_events;
5617113dcb4SGlenn Strauss 
5627113dcb4SGlenn Strauss     /* get the events of the file descriptors */
5637113dcb4SGlenn Strauss     if ((ret = port_getn(pfd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) {
5647113dcb4SGlenn Strauss         /* if errno == ETIME and available_event == wait_for_events we didn't get any events */
5657113dcb4SGlenn Strauss         /* for other errors we didn't get any events either */
5667113dcb4SGlenn Strauss         if (!(errno == ETIME && wait_for_events != available_events)) return ret;
5677113dcb4SGlenn Strauss     }
5687113dcb4SGlenn Strauss 
5697113dcb4SGlenn Strauss     for (int i = 0; i < (int)available_events; ++i) {
5707113dcb4SGlenn Strauss         int fd = (int)ev->port_events[i].portev_object;
5717113dcb4SGlenn Strauss         fdnode * const fdn = ev->fdarray[fd];
5727113dcb4SGlenn Strauss         const intptr_t ud = (intptr_t)ev->port_events[i].portev_user;
5737113dcb4SGlenn Strauss         int revents = ev->port_events[i].portev_events;
5747113dcb4SGlenn Strauss         if (0 == ((uintptr_t)fdn & 0x3)) {
5757113dcb4SGlenn Strauss             if (port_associate(pfd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud) < 0)
5767113dcb4SGlenn Strauss                 log_error(ev->errh,__FILE__,__LINE__,"port_associate failed");
5777113dcb4SGlenn Strauss             (*fdn->handler)(fdn->ctx, revents);
5787113dcb4SGlenn Strauss         }
5797113dcb4SGlenn Strauss         else {
5807113dcb4SGlenn Strauss             fdn->fde_ndx = -1;
5817113dcb4SGlenn Strauss         }
5827113dcb4SGlenn Strauss     }
5837113dcb4SGlenn Strauss     return available_events;
5847113dcb4SGlenn Strauss }
5857113dcb4SGlenn Strauss 
5867113dcb4SGlenn Strauss __attribute_cold__
5877113dcb4SGlenn Strauss static void
fdevent_solaris_port_free(fdevents * ev)5887113dcb4SGlenn Strauss fdevent_solaris_port_free (fdevents *ev)
5897113dcb4SGlenn Strauss {
5907113dcb4SGlenn Strauss     close(ev->port_fd);
5917113dcb4SGlenn Strauss     free(ev->port_events);
5927113dcb4SGlenn Strauss }
5937113dcb4SGlenn Strauss 
5947113dcb4SGlenn Strauss __attribute_cold__
5957113dcb4SGlenn Strauss static int
fdevent_solaris_port_init(fdevents * ev)5967113dcb4SGlenn Strauss fdevent_solaris_port_init (fdevents *ev)
5977113dcb4SGlenn Strauss {
5987113dcb4SGlenn Strauss     force_assert(POLLIN    == FDEVENT_IN);
5997113dcb4SGlenn Strauss     force_assert(POLLPRI   == FDEVENT_PRI);
6007113dcb4SGlenn Strauss     force_assert(POLLOUT   == FDEVENT_OUT);
6017113dcb4SGlenn Strauss     force_assert(POLLERR   == FDEVENT_ERR);
6027113dcb4SGlenn Strauss     force_assert(POLLHUP   == FDEVENT_HUP);
6037113dcb4SGlenn Strauss     force_assert(POLLNVAL  == FDEVENT_NVAL);
6047113dcb4SGlenn Strauss   #ifdef POLLRDHUP
6057113dcb4SGlenn Strauss     force_assert(POLLRDHUP == FDEVENT_RDHUP);
6067113dcb4SGlenn Strauss   #endif
6077113dcb4SGlenn Strauss 
6087113dcb4SGlenn Strauss     ev->type        = FDEVENT_HANDLER_SOLARIS_PORT;
6097113dcb4SGlenn Strauss     ev->event_set   = fdevent_solaris_port_event_set;
6107113dcb4SGlenn Strauss     ev->event_del   = fdevent_solaris_port_event_del;
6117113dcb4SGlenn Strauss     ev->poll        = fdevent_solaris_port_poll;
6127113dcb4SGlenn Strauss     ev->free        = fdevent_solaris_port_free;
6135e14db43SGlenn Strauss     ev->port_events = ck_calloc(ev->maxfds, sizeof(*ev->port_events));
6147113dcb4SGlenn Strauss 
6157113dcb4SGlenn Strauss     if ((ev->port_fd = port_create()) < 0) return -1;
6167113dcb4SGlenn Strauss 
6177113dcb4SGlenn Strauss     return 0;
6187113dcb4SGlenn Strauss }
6197113dcb4SGlenn Strauss 
6207113dcb4SGlenn Strauss #endif /* FDEVENT_USE_SOLARIS_PORT */
6217113dcb4SGlenn Strauss 
6227113dcb4SGlenn Strauss 
6237113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
6247113dcb4SGlenn Strauss 
6257113dcb4SGlenn Strauss #include <sys/devpoll.h>
6267113dcb4SGlenn Strauss #include <sys/ioctl.h>
6277113dcb4SGlenn Strauss #include <fcntl.h>
6287113dcb4SGlenn Strauss 
6297113dcb4SGlenn Strauss static int
fdevent_solaris_devpoll_event_del(fdevents * ev,fdnode * fdn)6307113dcb4SGlenn Strauss fdevent_solaris_devpoll_event_del (fdevents *ev, fdnode *fdn)
6317113dcb4SGlenn Strauss {
6327113dcb4SGlenn Strauss     struct pollfd pfd;
6337113dcb4SGlenn Strauss     pfd.fd = fdn->fd;
6347113dcb4SGlenn Strauss     pfd.events = POLLREMOVE;
6357113dcb4SGlenn Strauss     pfd.revents = 0;
6367113dcb4SGlenn Strauss     return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
6377113dcb4SGlenn Strauss }
6387113dcb4SGlenn Strauss 
6397113dcb4SGlenn Strauss static int
fdevent_solaris_devpoll_event_set(fdevents * ev,fdnode * fdn,int events)6407113dcb4SGlenn Strauss fdevent_solaris_devpoll_event_set (fdevents *ev, fdnode *fdn, int events)
6417113dcb4SGlenn Strauss {
6427113dcb4SGlenn Strauss     struct pollfd pfd;
6437113dcb4SGlenn Strauss     pfd.fd = fdn->fde_ndx = fdn->fd;
6447113dcb4SGlenn Strauss   #ifndef POLLRDHUP
6457113dcb4SGlenn Strauss     events &= ~FDEVENT_RDHUP;
6467113dcb4SGlenn Strauss   #endif
6477113dcb4SGlenn Strauss     pfd.events = events;
6487113dcb4SGlenn Strauss     pfd.revents = 0;
6497113dcb4SGlenn Strauss     return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
6507113dcb4SGlenn Strauss }
6517113dcb4SGlenn Strauss 
6527113dcb4SGlenn Strauss static int
fdevent_solaris_devpoll_poll(fdevents * ev,int timeout_ms)6537113dcb4SGlenn Strauss fdevent_solaris_devpoll_poll (fdevents *ev, int timeout_ms)
6547113dcb4SGlenn Strauss {
6557113dcb4SGlenn Strauss     fdnode ** const fdarray = ev->fdarray;
6567113dcb4SGlenn Strauss     struct pollfd * const devpollfds = ev->devpollfds;
6577113dcb4SGlenn Strauss     struct dvpoll dopoll;
6587113dcb4SGlenn Strauss 
6597113dcb4SGlenn Strauss     dopoll.dp_timeout = timeout_ms;
6607113dcb4SGlenn Strauss     dopoll.dp_nfds = ev->maxfds - 1;
6617113dcb4SGlenn Strauss     dopoll.dp_fds = devpollfds;
6627113dcb4SGlenn Strauss 
6637113dcb4SGlenn Strauss     const int n = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
6647113dcb4SGlenn Strauss 
6657113dcb4SGlenn Strauss     for (int i = 0; i < n; ++i) {
6667113dcb4SGlenn Strauss         fdnode * const fdn = fdarray[devpollfds[i].fd];
6677113dcb4SGlenn Strauss         int revents = devpollfds[i].revents;
6687113dcb4SGlenn Strauss         if (0 == ((uintptr_t)fdn & 0x3))
6697113dcb4SGlenn Strauss             (*fdn->handler)(fdn->ctx, revents);
6707113dcb4SGlenn Strauss     }
6717113dcb4SGlenn Strauss     return n;
6727113dcb4SGlenn Strauss }
6737113dcb4SGlenn Strauss 
6747113dcb4SGlenn Strauss __attribute_cold__
6757113dcb4SGlenn Strauss static int
fdevent_solaris_devpoll_reset(fdevents * ev)6767113dcb4SGlenn Strauss fdevent_solaris_devpoll_reset (fdevents *ev)
6777113dcb4SGlenn Strauss {
6787113dcb4SGlenn Strauss     /* a forked process does only inherit the filedescriptor,
6797113dcb4SGlenn Strauss      * but every operation on the device will lead to a EACCES */
6807113dcb4SGlenn Strauss     ev->devpoll_fd = fdevent_open_cloexec("/dev/poll", 1, O_RDWR, 0);
6817113dcb4SGlenn Strauss     return (ev->devpoll_fd >= 0) ? 0 : -1;
6827113dcb4SGlenn Strauss }
6837113dcb4SGlenn Strauss 
6847113dcb4SGlenn Strauss __attribute_cold__
6857113dcb4SGlenn Strauss static void
fdevent_solaris_devpoll_free(fdevents * ev)6867113dcb4SGlenn Strauss fdevent_solaris_devpoll_free (fdevents *ev)
6877113dcb4SGlenn Strauss {
6887113dcb4SGlenn Strauss     free(ev->devpollfds);
6897113dcb4SGlenn Strauss     close(ev->devpoll_fd);
6907113dcb4SGlenn Strauss }
6917113dcb4SGlenn Strauss 
6927113dcb4SGlenn Strauss __attribute_cold__
6937113dcb4SGlenn Strauss static int
fdevent_solaris_devpoll_init(fdevents * ev)6947113dcb4SGlenn Strauss fdevent_solaris_devpoll_init (fdevents *ev)
6957113dcb4SGlenn Strauss {
6967113dcb4SGlenn Strauss     force_assert(POLLIN    == FDEVENT_IN);
6977113dcb4SGlenn Strauss     force_assert(POLLPRI   == FDEVENT_PRI);
6987113dcb4SGlenn Strauss     force_assert(POLLOUT   == FDEVENT_OUT);
6997113dcb4SGlenn Strauss     force_assert(POLLERR   == FDEVENT_ERR);
7007113dcb4SGlenn Strauss     force_assert(POLLHUP   == FDEVENT_HUP);
7017113dcb4SGlenn Strauss     force_assert(POLLNVAL  == FDEVENT_NVAL);
7027113dcb4SGlenn Strauss   #ifdef POLLRDHUP
7037113dcb4SGlenn Strauss     force_assert(POLLRDHUP == FDEVENT_RDHUP);
7047113dcb4SGlenn Strauss   #endif
7057113dcb4SGlenn Strauss 
7067113dcb4SGlenn Strauss     ev->type       = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
7077113dcb4SGlenn Strauss     ev->event_set  = fdevent_solaris_devpoll_event_set;
7087113dcb4SGlenn Strauss     ev->event_del  = fdevent_solaris_devpoll_event_del;
7097113dcb4SGlenn Strauss     ev->poll       = fdevent_solaris_devpoll_poll;
7107113dcb4SGlenn Strauss     ev->reset      = fdevent_solaris_devpoll_reset;
7117113dcb4SGlenn Strauss     ev->free       = fdevent_solaris_devpoll_free;
7127113dcb4SGlenn Strauss     ev->devpoll_fd = -1;
7135e14db43SGlenn Strauss     ev->devpollfds = ck_calloc(ev->maxfds, sizeof(*ev->devpollfds));
7147113dcb4SGlenn Strauss     return 0;
7157113dcb4SGlenn Strauss }
7167113dcb4SGlenn Strauss 
7177113dcb4SGlenn Strauss #endif /* FDEVENT_USE_SOLARIS_DEVPOLL */
7187113dcb4SGlenn Strauss 
7197113dcb4SGlenn Strauss 
7207113dcb4SGlenn Strauss #ifdef FDEVENT_USE_POLL
7217113dcb4SGlenn Strauss 
7227113dcb4SGlenn Strauss #ifdef HAVE_POLL_H
7237113dcb4SGlenn Strauss #include <poll.h>
7247113dcb4SGlenn Strauss #else
7257113dcb4SGlenn Strauss #include <sys/poll.h>
7267113dcb4SGlenn Strauss #endif
7277113dcb4SGlenn Strauss 
7287113dcb4SGlenn Strauss static int
fdevent_poll_event_del(fdevents * ev,fdnode * fdn)7297113dcb4SGlenn Strauss fdevent_poll_event_del (fdevents *ev, fdnode *fdn)
7307113dcb4SGlenn Strauss {
7317113dcb4SGlenn Strauss     int fd = fdn->fd;
7327113dcb4SGlenn Strauss     int k = fdn->fde_ndx;
7337113dcb4SGlenn Strauss     if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
7347113dcb4SGlenn Strauss         return (errno = EINVAL, -1);
7357113dcb4SGlenn Strauss 
7367113dcb4SGlenn Strauss     ev->pollfds[k].fd = -1;
7377113dcb4SGlenn Strauss     /* ev->pollfds[k].events = 0; */
7387113dcb4SGlenn Strauss     /* ev->pollfds[k].revents = 0; */
7397113dcb4SGlenn Strauss 
7407113dcb4SGlenn Strauss     if (ev->unused.size == ev->unused.used) {
741c412bb59SGlenn Strauss         ck_realloc_u32((void **)&ev->unused.ptr, ev->unused.size,
742c412bb59SGlenn Strauss                        16, sizeof(*ev->unused.ptr));
7437113dcb4SGlenn Strauss         ev->unused.size += 16;
7447113dcb4SGlenn Strauss     }
7457113dcb4SGlenn Strauss 
7467113dcb4SGlenn Strauss     ev->unused.ptr[ev->unused.used++] = k;
7477113dcb4SGlenn Strauss 
7487113dcb4SGlenn Strauss     return 0;
7497113dcb4SGlenn Strauss }
7507113dcb4SGlenn Strauss 
7517113dcb4SGlenn Strauss static int
fdevent_poll_event_set(fdevents * ev,fdnode * fdn,int events)7527113dcb4SGlenn Strauss fdevent_poll_event_set (fdevents *ev, fdnode *fdn, int events)
7537113dcb4SGlenn Strauss {
7547113dcb4SGlenn Strauss     int fd = fdn->fd;
7557113dcb4SGlenn Strauss     int k = fdn->fde_ndx;
7567113dcb4SGlenn Strauss 
7577113dcb4SGlenn Strauss   #ifndef POLLRDHUP
7587113dcb4SGlenn Strauss     events &= ~FDEVENT_RDHUP;
7597113dcb4SGlenn Strauss   #endif
7607113dcb4SGlenn Strauss 
7617113dcb4SGlenn Strauss     if (k >= 0) {
7627113dcb4SGlenn Strauss         if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
7637113dcb4SGlenn Strauss             return (errno = EINVAL, -1);
7647113dcb4SGlenn Strauss         ev->pollfds[k].events = events;
7657113dcb4SGlenn Strauss         return 0;
7667113dcb4SGlenn Strauss     }
7677113dcb4SGlenn Strauss 
7687113dcb4SGlenn Strauss     if (ev->unused.used > 0) {
7697113dcb4SGlenn Strauss         k = ev->unused.ptr[--ev->unused.used];
7707113dcb4SGlenn Strauss     }
7717113dcb4SGlenn Strauss     else {
7727113dcb4SGlenn Strauss         if (ev->size == ev->used) {
773c412bb59SGlenn Strauss             ck_realloc_u32((void **)&ev->pollfds, ev->size,
774c412bb59SGlenn Strauss                            16, sizeof(*ev->pollfds));
7757113dcb4SGlenn Strauss             ev->size += 16;
7767113dcb4SGlenn Strauss         }
7777113dcb4SGlenn Strauss 
7787113dcb4SGlenn Strauss         k = ev->used++;
7797113dcb4SGlenn Strauss     }
7807113dcb4SGlenn Strauss 
7817113dcb4SGlenn Strauss     fdn->fde_ndx = k;
7827113dcb4SGlenn Strauss     ev->pollfds[k].fd = fd;
7837113dcb4SGlenn Strauss     ev->pollfds[k].events = events;
7847113dcb4SGlenn Strauss 
7857113dcb4SGlenn Strauss     return 0;
7867113dcb4SGlenn Strauss }
7877113dcb4SGlenn Strauss 
7887113dcb4SGlenn Strauss static int
fdevent_poll_poll(fdevents * ev,int timeout_ms)7897113dcb4SGlenn Strauss fdevent_poll_poll (fdevents *ev, int timeout_ms)
7907113dcb4SGlenn Strauss {
791*32f0e26dSGlenn Strauss     const int n = poll(ev->pollfds, ev->used, timeout_ms);
7927113dcb4SGlenn Strauss     fdnode ** const fdarray = ev->fdarray;
793*32f0e26dSGlenn Strauss     for (int i = 0, m = 0; m < n; ++i, ++m) {
794*32f0e26dSGlenn Strauss         struct pollfd * const restrict pfds = ev->pollfds;
795*32f0e26dSGlenn Strauss         while (0 == pfds[i].revents) ++i;
7967113dcb4SGlenn Strauss         fdnode *fdn = fdarray[pfds[i].fd];
7977113dcb4SGlenn Strauss         if (0 == ((uintptr_t)fdn & 0x3))
7987113dcb4SGlenn Strauss             (*fdn->handler)(fdn->ctx, pfds[i].revents);
7997113dcb4SGlenn Strauss     }
8007113dcb4SGlenn Strauss     return n;
8017113dcb4SGlenn Strauss }
8027113dcb4SGlenn Strauss 
8037113dcb4SGlenn Strauss __attribute_cold__
8047113dcb4SGlenn Strauss static void
fdevent_poll_free(fdevents * ev)8057113dcb4SGlenn Strauss fdevent_poll_free (fdevents *ev)
8067113dcb4SGlenn Strauss {
8077113dcb4SGlenn Strauss     free(ev->pollfds);
8087113dcb4SGlenn Strauss     if (ev->unused.ptr) free(ev->unused.ptr);
8097113dcb4SGlenn Strauss }
8107113dcb4SGlenn Strauss 
8117113dcb4SGlenn Strauss __attribute_cold__
8127113dcb4SGlenn Strauss static int
fdevent_poll_init(fdevents * ev)8137113dcb4SGlenn Strauss fdevent_poll_init (fdevents *ev)
8147113dcb4SGlenn Strauss {
8157113dcb4SGlenn Strauss     force_assert(POLLIN    == FDEVENT_IN);
8167113dcb4SGlenn Strauss     force_assert(POLLPRI   == FDEVENT_PRI);
8177113dcb4SGlenn Strauss     force_assert(POLLOUT   == FDEVENT_OUT);
8187113dcb4SGlenn Strauss     force_assert(POLLERR   == FDEVENT_ERR);
8197113dcb4SGlenn Strauss     force_assert(POLLHUP   == FDEVENT_HUP);
8207113dcb4SGlenn Strauss     force_assert(POLLNVAL  == FDEVENT_NVAL);
8217113dcb4SGlenn Strauss   #ifdef POLLRDHUP
8227113dcb4SGlenn Strauss     force_assert(POLLRDHUP == FDEVENT_RDHUP);
8237113dcb4SGlenn Strauss   #endif
8247113dcb4SGlenn Strauss 
8257113dcb4SGlenn Strauss     ev->type      = FDEVENT_HANDLER_POLL;
8267113dcb4SGlenn Strauss     ev->event_set = fdevent_poll_event_set;
8277113dcb4SGlenn Strauss     ev->event_del = fdevent_poll_event_del;
8287113dcb4SGlenn Strauss     ev->poll      = fdevent_poll_poll;
8297113dcb4SGlenn Strauss     ev->free      = fdevent_poll_free;
8307113dcb4SGlenn Strauss     return 0;
8317113dcb4SGlenn Strauss }
8327113dcb4SGlenn Strauss 
8337113dcb4SGlenn Strauss #endif /* FDEVENT_USE_POLL */
8347113dcb4SGlenn Strauss 
8357113dcb4SGlenn Strauss 
8367113dcb4SGlenn Strauss #ifdef FDEVENT_USE_SELECT
8377113dcb4SGlenn Strauss 
8387113dcb4SGlenn Strauss #include "sys-time.h"
8397113dcb4SGlenn Strauss 
8407113dcb4SGlenn Strauss __attribute_cold__
8417113dcb4SGlenn Strauss static int
fdevent_select_reset(fdevents * ev)8427113dcb4SGlenn Strauss fdevent_select_reset (fdevents *ev)
8437113dcb4SGlenn Strauss {
8447113dcb4SGlenn Strauss     FD_ZERO(&(ev->select_set_read));
8457113dcb4SGlenn Strauss     FD_ZERO(&(ev->select_set_write));
8467113dcb4SGlenn Strauss     FD_ZERO(&(ev->select_set_error));
8477113dcb4SGlenn Strauss     ev->select_max_fd = -1;
8487113dcb4SGlenn Strauss     return 0;
8497113dcb4SGlenn Strauss }
8507113dcb4SGlenn Strauss 
8517113dcb4SGlenn Strauss static int
fdevent_select_event_del(fdevents * ev,fdnode * fdn)8527113dcb4SGlenn Strauss fdevent_select_event_del (fdevents *ev, fdnode *fdn)
8537113dcb4SGlenn Strauss {
8547113dcb4SGlenn Strauss     int fd = fdn->fd;
8557113dcb4SGlenn Strauss     FD_CLR(fd, &(ev->select_set_read));
8567113dcb4SGlenn Strauss     FD_CLR(fd, &(ev->select_set_write));
8577113dcb4SGlenn Strauss     FD_CLR(fd, &(ev->select_set_error));
8587113dcb4SGlenn Strauss     return 0;
8597113dcb4SGlenn Strauss }
8607113dcb4SGlenn Strauss 
8617113dcb4SGlenn Strauss static int
fdevent_select_event_set(fdevents * ev,fdnode * fdn,int events)8627113dcb4SGlenn Strauss fdevent_select_event_set (fdevents *ev, fdnode *fdn, int events)
8637113dcb4SGlenn Strauss {
8647113dcb4SGlenn Strauss     int fd = fdn->fde_ndx = fdn->fd;
8657113dcb4SGlenn Strauss 
8667113dcb4SGlenn Strauss     /* we should be protected by max-fds, but you never know */
8677113dcb4SGlenn Strauss     force_assert(fd < ((int)FD_SETSIZE));
8687113dcb4SGlenn Strauss 
8697113dcb4SGlenn Strauss     if (events & FDEVENT_IN)
8707113dcb4SGlenn Strauss         FD_SET(fd, &(ev->select_set_read));
8717113dcb4SGlenn Strauss     else
8727113dcb4SGlenn Strauss         FD_CLR(fd, &(ev->select_set_read));
8737113dcb4SGlenn Strauss 
8747113dcb4SGlenn Strauss     if (events & FDEVENT_OUT)
8757113dcb4SGlenn Strauss         FD_SET(fd, &(ev->select_set_write));
8767113dcb4SGlenn Strauss     else
8777113dcb4SGlenn Strauss         FD_CLR(fd, &(ev->select_set_write));
8787113dcb4SGlenn Strauss 
8797113dcb4SGlenn Strauss     FD_SET(fd, &(ev->select_set_error));
8807113dcb4SGlenn Strauss 
8817113dcb4SGlenn Strauss     if (fd > ev->select_max_fd) ev->select_max_fd = fd;
8827113dcb4SGlenn Strauss 
8837113dcb4SGlenn Strauss     return 0;
8847113dcb4SGlenn Strauss }
8857113dcb4SGlenn Strauss 
8867113dcb4SGlenn Strauss static int
fdevent_select_poll(fdevents * ev,int timeout_ms)8877113dcb4SGlenn Strauss fdevent_select_poll (fdevents *ev, int timeout_ms)
8887113dcb4SGlenn Strauss {
8897113dcb4SGlenn Strauss     struct timeval tv;
8907113dcb4SGlenn Strauss     tv.tv_sec =  timeout_ms / 1000;
8917113dcb4SGlenn Strauss     tv.tv_usec = (timeout_ms % 1000) * 1000;
8927113dcb4SGlenn Strauss 
8937113dcb4SGlenn Strauss     ev->select_read  = ev->select_set_read;
8947113dcb4SGlenn Strauss     ev->select_write = ev->select_set_write;
8957113dcb4SGlenn Strauss     ev->select_error = ev->select_set_error;
8967113dcb4SGlenn Strauss 
897d74025f8SGlenn Strauss     const int nfds = ev->select_max_fd + 1;
898d74025f8SGlenn Strauss     const int n =
899d74025f8SGlenn Strauss       select(nfds, &ev->select_read, &ev->select_write, &ev->select_error, &tv);
900d74025f8SGlenn Strauss     if (n <= 0) return n;
901d74025f8SGlenn Strauss     for (int ndx = -1, i = n; ++ndx < nfds; ) {
902d74025f8SGlenn Strauss         int revents = 0;
903d74025f8SGlenn Strauss         if (FD_ISSET(ndx, &ev->select_read))  revents |= FDEVENT_IN;
904d74025f8SGlenn Strauss         if (FD_ISSET(ndx, &ev->select_write)) revents |= FDEVENT_OUT;
905d74025f8SGlenn Strauss         if (FD_ISSET(ndx, &ev->select_error)) revents |= FDEVENT_ERR;
906d74025f8SGlenn Strauss         if (revents) {
907d74025f8SGlenn Strauss             const fdnode *fdn = ev->fdarray[ndx];
908d74025f8SGlenn Strauss             if (0 == ((uintptr_t)fdn & 0x3))
9097113dcb4SGlenn Strauss                 (*fdn->handler)(fdn->ctx, revents);
910d74025f8SGlenn Strauss             if (0 == --i)
911d74025f8SGlenn Strauss                 break;
9127113dcb4SGlenn Strauss         }
9137113dcb4SGlenn Strauss     }
9147113dcb4SGlenn Strauss     return n;
9157113dcb4SGlenn Strauss }
9167113dcb4SGlenn Strauss 
9177113dcb4SGlenn Strauss __attribute_cold__
fdevent_select_init(fdevents * ev)9187113dcb4SGlenn Strauss static int fdevent_select_init (fdevents *ev)
9197113dcb4SGlenn Strauss {
9207113dcb4SGlenn Strauss     ev->type      = FDEVENT_HANDLER_SELECT;
9217113dcb4SGlenn Strauss     ev->event_set = fdevent_select_event_set;
9227113dcb4SGlenn Strauss     ev->event_del = fdevent_select_event_del;
9237113dcb4SGlenn Strauss     ev->poll      = fdevent_select_poll;
9247113dcb4SGlenn Strauss     ev->reset     = fdevent_select_reset;
9257113dcb4SGlenn Strauss     return 0;
9267113dcb4SGlenn Strauss }
9277113dcb4SGlenn Strauss 
9287113dcb4SGlenn Strauss #endif /* FDEVENT_USE_SELECT */
929