[core] retry on some fdevent set/del temporary err
[lighttpd.git] / src / fdevent_freebsd_kqueue.c
blob8960a19b9c913bda123d58730eeccddade45ffab
1 #include "first.h"
3 #include "fdevent_impl.h"
4 #include "fdevent.h"
5 #include "buffer.h"
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
12 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
14 # include <sys/event.h>
15 # include <sys/time.h>
17 __attribute_cold__
18 static void fdevent_freebsd_kqueue_free(fdevents *ev) {
19 close(ev->kq_fd);
20 free(ev->kq_results);
23 static int fdevent_freebsd_kqueue_event_del(fdevents *ev, fdnode *fdn) {
24 struct kevent kev[2];
25 struct timespec ts = {0, 0};
26 int fd = fdn->fd;
27 int n = 0;
28 int oevents = fdn->events;
30 if (oevents & FDEVENT_IN) {
31 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
32 n++;
34 if (oevents & FDEVENT_OUT) {
35 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
36 n++;
39 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
40 /*(kevent() changelist still processed on EINTR,
41 * but EINTR should not be received since 0 == nevents)*/
44 static int fdevent_freebsd_kqueue_event_set(fdevents *ev, fdnode *fdn, int events) {
45 struct kevent kev[2];
46 struct timespec ts = {0, 0};
47 int fd = fdn->fde_ndx = fdn->fd;
48 int n = 0;
49 int oevents = fdn->events;
50 int addevents = events & ~oevents;
51 int delevents = ~events & oevents;
53 if (addevents & FDEVENT_IN) {
54 EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn);
55 n++;
56 } else if (delevents & FDEVENT_IN) {
57 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
58 n++;
60 if (addevents & FDEVENT_OUT) {
61 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn);
62 n++;
63 } else if (delevents & FDEVENT_OUT) {
64 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
65 n++;
68 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
69 /*(kevent() changelist still processed on EINTR,
70 * but EINTR should not be received since 0 == nevents)*/
73 static int fdevent_freebsd_kqueue_poll(fdevents * const ev, int timeout_ms) {
74 server * const srv = ev->srv;
75 struct timespec ts;
76 int n;
78 ts.tv_sec = timeout_ms / 1000;
79 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
81 n = kevent(ev->kq_fd, NULL, 0, ev->kq_results, ev->maxfds, &ts);
83 for (int i = 0; i < n; ++i) {
84 fdnode * const fdn = (fdnode *)ev->kq_results[i].udata;
85 int filt = ev->kq_results[i].filter;
86 int e = ev->kq_results[i].flags;
87 if ((fdevent_handler)NULL != fdn->handler) {
88 int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT;
89 if (e & EV_EOF)
90 revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP);
91 if (e & EV_ERROR)
92 revents |= FDEVENT_ERR;
93 (*fdn->handler)(srv, fdn->ctx, revents);
96 return n;
99 __attribute_cold__
100 static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
101 return (-1 != (ev->kq_fd = kqueue())) ? 0 : -1;
104 __attribute_cold__
105 int fdevent_freebsd_kqueue_init(fdevents *ev) {
106 ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE;
107 ev->event_set = fdevent_freebsd_kqueue_event_set;
108 ev->event_del = fdevent_freebsd_kqueue_event_del;
109 ev->poll = fdevent_freebsd_kqueue_poll;
110 ev->reset = fdevent_freebsd_kqueue_reset;
111 ev->free = fdevent_freebsd_kqueue_free;
112 ev->kq_fd = -1;
113 ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
114 force_assert(NULL != ev->kq_results);
115 return 0;
118 #endif