Wrap up version 1.3.3.
[minidlna.git] / kqueue.c
blob35b3f2b55548085382999d2628538e7446d71803
1 /*
2 * Copyright (c) 2017 Gleb Smirnoff <glebius@FreeBSD.org>
3 * Copyright (c) 2002-2017 Igor Sysoev
4 * Copyright (c) 2011-2017 Nginx, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/types.h>
30 #include <sys/event.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
38 #include "event.h"
39 #include "log.h"
41 static int kqueue_set(struct event *, short, u_short, u_int);
43 static event_module_init_t kqueue_init;
44 static event_module_fini_t kqueue_fini;
45 static event_module_add_t kqueue_add;
46 static event_module_del_t kqueue_del;
47 static event_module_process_t kqueue_process;
49 static int kq;
50 static struct kevent *change_list;
51 static struct kevent *event_list;
52 static u_int nchanges;
54 #define MAXCHANGES 128
55 #define MAXEVENTS 128
57 struct event_module event_module = {
58 .add = kqueue_add,
59 .del = kqueue_del,
60 .process = kqueue_process,
61 .init = kqueue_init,
62 .fini = kqueue_fini,
65 static int
66 kqueue_init(void)
69 kq = kqueue();
70 if (kq == -1)
71 return (errno);
73 change_list = calloc(MAXCHANGES, sizeof(struct kevent));
74 event_list = calloc(MAXEVENTS, sizeof(struct kevent));
75 if (change_list == NULL || event_list == NULL)
76 return (ENOMEM);
78 nchanges = 0;
80 return (0);
83 static void
84 kqueue_fini()
87 (void )close(kq);
88 kq = -1;
90 free(change_list);
91 free(event_list);
92 change_list = NULL;
93 event_list = NULL;
94 nchanges = 0;
97 static int
98 kqueue_add(struct event *ev)
100 u_int fflags;
101 u_short flags;
103 if (ev->rdwr == EVFILT_VNODE) {
104 flags = EV_ADD | EV_ENABLE | EV_CLEAR;
105 fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND;
106 } else {
107 flags = EV_ADD | EV_ENABLE;
108 fflags = 0;
111 DPRINTF(E_DEBUG, L_GENERAL, "kqueue_add %d\n", ev->fd);
112 return (kqueue_set(ev, ev->rdwr, flags, fflags));
115 static int
116 kqueue_del(struct event *ev, int flags)
120 * If the event is still not passed to a kernel,
121 * we will not pass it.
123 assert(ev->fd >= 0);
124 if (ev->index < nchanges &&
125 change_list[ev->index].udata == ev) {
126 if (ev->index < --nchanges) {
127 struct event *ev0;
129 ev0 = (struct event *)change_list[nchanges].udata;
130 change_list[ev->index] = change_list[nchanges];
131 ev0->index = ev->index;
133 return (0);
137 * when the file descriptor is closed the kqueue automatically deletes
138 * its filters so we do not need to delete explicitly the event
139 * before the closing the file descriptor.
141 if (flags & EV_FLAG_CLOSING)
142 return (0);
144 DPRINTF(E_DEBUG, L_GENERAL, "kqueue_del %d\n", ev->fd);
145 return (kqueue_set(ev, ev->rdwr, EV_DELETE, 0));
148 static int
149 kqueue_set(struct event *ev, short filter, u_short flags, u_int fflags)
151 struct kevent *kev;
152 struct timespec ts;
154 if (nchanges >= MAXCHANGES) {
155 DPRINTF(E_INFO, L_GENERAL, "kqueue change list is filled up\n");
157 ts.tv_sec = 0;
158 ts.tv_nsec = 0;
160 if (kevent(kq, change_list, (int) nchanges, NULL, 0, &ts) == -1) {
161 DPRINTF(E_ERROR, L_GENERAL,"kevent() failed: %s\n", strerror(errno));
162 return (errno);
164 nchanges = 0;
167 kev = &change_list[nchanges];
168 kev->ident = ev->fd;
169 kev->filter = filter;
170 kev->flags = flags;
171 kev->udata = ev;
172 kev->fflags = fflags;
173 kev->data = 0;
175 ev->index = nchanges++;
177 return (0);
180 static int
181 kqueue_process(struct timeval *tv)
183 struct event *ev;
184 int events, n, i;
185 struct timespec ts;
187 n = (int) nchanges;
188 nchanges = 0;
190 TIMEVAL_TO_TIMESPEC(tv, &ts);
192 DPRINTF(E_DEBUG, L_GENERAL, "kevent timer: %lu.%06lu, changes: %d\n",
193 ts.tv_sec, ts.tv_nsec, n);
195 events = kevent(kq, change_list, n, event_list, MAXEVENTS, &ts);
197 if (events == -1) {
198 if (errno == EINTR)
199 return (errno);
200 DPRINTF(E_FATAL, L_GENERAL, "kevent(): %s. EXITING\n", strerror(errno));
203 DPRINTF(E_DEBUG, L_GENERAL, "kevent events: %d\n", events);
205 for (i = 0; i < events; i++) {
206 if (event_list[i].flags & EV_ERROR) {
207 DPRINTF(E_ERROR, L_GENERAL,
208 "kevent() error %d on %d filter:%d flags:0x%x\n",
209 (int)event_list[i].data, (int)event_list[i].ident,
210 event_list[i].filter, event_list[i].flags);
211 continue;
214 ev = (struct event *)event_list[i].udata;
216 switch (event_list[i].filter) {
217 case EVFILT_READ:
218 case EVFILT_WRITE:
219 ev->process(ev);
220 break;
221 case EVFILT_VNODE:
222 ev->process_vnode(ev, event_list[i].fflags);
223 break;
224 default:
225 DPRINTF(E_ERROR, L_GENERAL,
226 "unexpected kevent() filter %d",
227 event_list[i].filter);
228 continue;
232 return (0);