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